Rewrite Cascade-style local file links in a Markdown file to GitHub URLs.
Useful for fixing up PR descriptions drafted with the help of Cascade (or any
tool that emits links like [label](cci:7://file:///abs/path/file.js:...)),
turning them into real https://github.com/owner/repo/blob/... links.
- Python 3.10+ (uses
tuple[str, str]syntax). No third-party packages. giton$PATH.
-
Clone this repo wherever you keep tools:
git clone https://github.com/ejones23/remote-ify-links.git
-
Make the script available as a command. Pick whichever style fits your workflow — the script is self-contained, so any of these work:
- Symlink into a directory on your
$PATH(e.g.~/.local/bin,~/bin,/usr/local/bin):ln -s "$(pwd)/remote-ify-links/remote-ify-links.py" /path/on/your/PATH/remote-ify-links - Add a shell alias in your shell rc file:
alias remote-ify-links="python3 /full/path/to/remote-ify-links/remote-ify-links.py"
- Add the repo directory to your
$PATHand rename or symlink the script to drop the.pyextension if you prefer. - Just invoke it directly with
python3 /path/to/remote-ify-links.py.
Whichever approach you use, the only requirement is that you can invoke the script from inside any git repo where you want to rewrite links.
- Symlink into a directory on your
Run the script from anywhere inside the git repo whose links you want to rewrite. The current branch is auto-detected as the link ref.
remote-ify-links input.md # print to stdout
remote-ify-links input.md -o out.md # write to a new file
remote-ify-links input.md --in-place # rewrite in place
remote-ify-links input.md --ref master # use a specific branch/tag/SHA
remote-ify-links input.md --remote origin # force a specific remote
cat input.md | remote-ify-links # read from stdin
remote-ify-links --refresh-cache # re-read this repo's remote URLThe script picks the GitHub owner/repo from the current branch's
configured upstream remote (git config branch.<name>.remote), not blindly
from origin. This matters when working in a fork:
origin https://github.com/upstream/repo.git # the project you're contributing to
fork https://github.com/me/repo.git # your personal fork (where the branch lives)
After git push -u fork my-feature, the script will produce links pointing
at github.com/me/repo/blob/my-feature/..., which is where the branch
actually lives during PR review. Linking against origin would 404 because
the branch was never pushed there.
If the current branch has no configured upstream remote, the script falls
back to origin and emits a warning. Pass --remote NAME to override
explicitly.
Three input shapes are recognized:
| Cascade format | Becomes |
|---|---|
[label](cci:7://file:///abs/path:0:0-0:0) |
[label](https://github.com/owner/repo/blob/<ref>/relpath) |
[label](cci:1://file:///abs/path:L1:C1-L2:C2) |
[label](https://github.com/owner/repo/blob/<ref>/relpath#L<L1>-L<L2>) |
`@/abs/path[:N[-M]]` (backticked citation) |
[<smart-label>](https://github.com/owner/repo/blob/<ref>/relpath[#L<N>[-L<M>]]) |
cci:7is a whole-file reference; the trailing:0:0-0:0is dropped.cci:1is a symbol/range reference. GitHub only supports line ranges, so column information is dropped. Single-line ranges become#L<n>instead of#L<n>-L<n>.- The backticked
@/abs/pathcitation form is what some Cascade prompt configs emit inline (e.g.`@/Users/me/proj/src/foo.py:5-10`). The visible label uses the file's basename when that basename uniquely identifies a single relpath in the document, otherwise the full repo-relative path. The line range is appended to the label so the rendered text keeps the same information density as the citation. Bare, un-backticked@/...references are left alone to avoid false positives in prose. - Links to paths outside the current repo are left unchanged (with a warning to stderr).
- Links already pointing at
https://github.com/...are left unchanged.
Unit tests live under tests/ and use only the standard library:
python3 -m unittest discover testsWhole-document regression cases live in tests/fixtures/ as paired
*.input.md / *.expected.md files. Add a new pair when you encounter a
real PR draft the script handles wrong, then fix the script until the
fixture round-trips.
Per-repo origin URL info is cached in ~/.cache/remote-ify-links/cache.json,
keyed by the repo's root path. The cache survives across multiple repos. To
rebuild it for the current repo, run with --refresh-cache.
MIT — do whatever you want with it.