owner/repo@ref:path

gref is the shorthand you already type in chat and CLIs, written down as a small, portable grammar tools can share.

Examples

kzu/sandbox
kzu/sandbox@v1.2.3:src/hello.cs
github.com/kzu/sandbox@main:program.cs
gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:run.cs
gitlab.com/kzu/runcs@main:program.cs
Piece Meaning
host/ Optional forge (github.com, gitlab.com, gist.github.com, …)
owner/repo Repository (or gist id)
@ref Optional branch, tag, or commit (may include /, e.g. feature/foo)
:path Optional file or directory inside the repo

Omitted host, ref, or path are filled in by the application (many tools default host to github.com).

Spec

The formal grammar and rules live in gref.md and on the versioned site:

gref.sh — latest published spec, with prior versions available from the version menu.

Used by

gref is the remote-ref shape used by:

  • go# — run file-based C# apps locally or from a remote ref (dnx go -- owner/repo@ref:path)
  • runfile — run C# programs from GitHub, Gist, or GitLab refs (dnx runfile owner/repo@ref:path)

Those tools may accept additional host-specific conveniences beyond the core format; the spec defines the portable string.

License

MIT — see license.txt.


Specification · v0.1.0

# gref **g**it-backed **ref**erences. A compact, human-writable string that identifies a path in a remote git-hosted repository — without requiring a full URL. ``` owner/repo@ref:path ``` ## Objectives gref aims to be: - **Obvious** — readable at a glance; looks like the shorthand people already type (`owner/repo`, `owner/repo@v1`, `owner/repo:path`). - **Minimal** — only the pieces needed to locate content: host, owner, repository, ref, and path. - **Portable** — the same string can be parsed by CLIs, package managers, agent tools, and config files. - **Host-friendly** — defaults to a two-segment `owner/repo` form, with an optional host prefix for Gist, GitLab, and other forges. gref specifies **string syntax and structure**. How a consumer downloads content, which ref or path to use when omitted, authentication, and caching are **application-defined**. ## Terminology | Term | Meaning | | --- | --- | | **host** | DNS name of the forge (e.g. `github.com`, `gitlab.com`) | | **owner** | Account, user, or organization | | **repo** | Repository name (or gist id on `gist.github.com`) | | **ref** | Branch, tag, or commit-ish after `@` | | **path** | Repository-relative file or directory path after `:`; trailing `/` means folder | ## Format The general form is: ``` [host/]owner/repo[@ref][:path] ``` Whitespace is not allowed anywhere in a gref. Matching is case-sensitive for all components except where a host itself treats names case-insensitively (application-defined when resolving). ### Minimal form ``` owner/repo ``` Implies no explicit host, ref, or path. Consumers apply their own defaults (see [Application defaults](#application-defaults-non-normative)). ### With ref ``` owner/repo@main owner/repo@v1.2.3 owner/repo@abc1234 owner/repo@feature/foo ``` `ref` is everything after the first `@` following `owner/repo`, up to (but not including) a following `:path`, if any. It must not contain whitespace or `:`. It **may** contain `/` (common in branch names). ### With path ``` owner/repo:src/app.cs owner/repo@v1:docs/readme.md owner/repo@main:src/ ``` `path` is everything after the first `:` that follows the repository segment (and optional `@ref`). Paths use `/` as the separator. A leading `/` is not required; consumers should treat `foo/bar` and `/foo/bar` as the same repository-relative path. A path that **ends with `/`** denotes a **folder** (tree) reference rather than a **file** (blob) reference. Consumers that resolve content should treat `src/app.cs` as a file and `src/` as a directory. ### With host ``` github.com/owner/repo@main:path gist.github.com/owner/gistid gitlab.com/owner/repo@main:path ``` When `host` is present it is a domain-like token: labels of alphanumerics and hyphens, separated by dots, ending with an alphabetic TLD of length ≥ 2. ## Components ### Host Optional. When omitted, the consumer supplies a default (commonly `github.com`). | Host | Notes | | --- | --- | | `github.com` | Typical default for two-segment `owner/repo` | | `gist.github.com` | `repo` is the gist id | | `gitlab.com` | Same shape as GitHub | Other hosts are valid in the grammar; resolution is application-defined. ### Owner Non-empty. Must not contain `/`, `@`, `:`, or whitespace. ### Repo Non-empty. Must not contain `@`, `:`, or whitespace. Must not contain `/` (a `/` after `owner/` starts a path only when using other URI forms — in gref, the repository name is a single segment). On `gist.github.com`, `repo` is the gist identifier. ### Ref Optional. Branch name, tag name, or other commit-ish accepted by the host. Must not contain `:` or whitespace. May contain `/`. When omitted, resolution of `ref` is application-defined. Implementations **MAY**: - default to the repository’s **default branch** (commonly `main` or `master`); - default to the **latest published version** (for example the newest release tag or package version the tool understands); or - **require** an explicit `@ref` and reject or error when it is missing. For reproducible shares (lockfiles, citations), prefer **tags** or **commit SHAs** over floating branch names. ### Path Optional. Repository-relative path to a file or directory. - If `path` does **not** end with `/`, it denotes a **file** (blob) reference. - If `path` **ends with `/`**, it denotes a **folder** (tree) reference. When omitted, the default path is application-defined (for example a well-known entry file, or the repository root as a whole). ## Grammar Normative structure (character classes for `owner` / `repo` / `host` are **structural**; see also [Common subset](#common-subset-informative)): ```abnf gref = [ host "/" ] owner "/" repo [ "@" ref ] [ ":" path ] host = label *( "." label ) "." tld label = alnum *63( alnum / "-" ) tld = 2*alpha owner = 1*( unreserved ) repo = 1*( unreserved ) ref = 1*( %x21-39 / %x3B-7E ) ; non-empty; no ":" or space path = 1*( %x21-7E ) ; non-empty; no space unreserved = %x21-2E / %x30-39 / %x3B-3F / %x41-7E ; printable ASCII except space, "/" (0x2F), ":" (0x3A), "@" (0x40) ; — i.e. no gref delimiters alnum = ALPHA / DIGIT alpha = %x41-5A / %x61-7A ``` **Parsing order:** 1. If the string is an absolute URL of a known forge shape, first [normalize it](#url-convenience-forms) into gref form, then parse. 2. Else match the gref grammar. A parse failure means the string is not a gref (it may still be a local path or another identifier — applications decide the fallback order). ### Common subset (informative) Many GitHub-oriented tools additionally restrict: | Component | Common restriction | | --- | --- | | `owner` | Starts with alphanumeric; hyphens allowed; max length 39 | | `repo` | Alphanumerics, `.`, `_`, `-`; max length 100 | These limits are **not** required by gref. Consumers talking to a specific API may tighten validation for that host. ## Examples ``` # Defaults for host / ref / path left to the application kzu/sandbox # Explicit ref and path (file) kzu/sandbox@v1.2.3:src/hello.cs kzu/sandbox@main:program.cs kzu/sandbox@feature/foo:src/app.cs # Folder path (trailing slash) kzu/sandbox@main:src/ kzu/sandbox@v1:docs/guides/ # Explicit host github.com/kzu/sandbox@main:hello.cs github.com/kzu/sandbox@main:src/ # GitHub Gist (repo = gist id) gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381 gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381:run.cs # GitLab gitlab.com/kzu/runcs@main:program.cs ``` ### Round-trip display A structured gref should format back to: ``` [host/]owner/repo[@ref][:path] ``` Omit optional parts that are unset. Do not invent defaults when serializing unless the application documents that behavior. ## URL convenience forms Consumers **MAY** accept absolute HTTPS URLs pasted from a browser and normalize them to gref form before parsing. ### GitHub blob URL (file) ``` https://github.com/{owner}/{repo}/blob/{ref}/{path} → github.com/{owner}/{repo}@{ref}:{path} ``` ### GitHub tree URL (folder) ``` https://github.com/{owner}/{repo}/tree/{ref}/{path} → github.com/{owner}/{repo}@{ref}:{path}/ ``` The trailing `/` on the gref path marks a folder reference. If the tree URL points at the repository root (`…/tree/{ref}` with no further path), applications **MAY** omit `:path` or use a host-specific root convention. ### GitHub Gist URL ``` https://gist.github.com/{owner}/{gistid} → gist.github.com/{owner}/{gistid} ``` ### GitLab blob URL (file) ``` https://gitlab.com/{owner}/{repo}/-/blob/{ref}/{path} → gitlab.com/{owner}/{repo}@{ref}:{path} ``` ### GitLab tree URL (folder) ``` https://gitlab.com/{owner}/{repo}/-/tree/{ref}/{path} → gitlab.com/{owner}/{repo}@{ref}:{path}/ ``` Other URL shapes are application-defined. Unknown hosts or shapes should not be forced into a gref. ## Comparison to related forms | Form | Example | Relationship | | --- | --- | --- | | Go / module path | `github.com/owner/repo` | Host + owner + repo; no `@ref:path` in the same way | | Git SSH | `git@github.com:owner/repo.git` | Transport URL, not a gref | | Raw content URL | `https://raw.githubusercontent.com/...` | Resolved artifact URL; gref is the *input* shorthand | gref is intentionally close to how developers already cite repository paths in chat and CLIs. ## Application defaults (non-normative) These defaults are **not** required by gref; they are policies of tools that resolve grefs to downloadable content. | Omitted | Common choices (implementations **MAY** pick any) | | --- | --- | | `host` | `github.com` | | `ref` | Repository **default branch** (`main` / `master`); or **latest published version** (e.g. newest release tag); or **require** `@ref` | | `path` | A conventional entry file, else repository root | No single default for `ref` is mandated: a CLI that tracks floating source may use the default branch; a package-style runner may pin “latest release”; a strict resolver may demand `@ref` every time. Local path disambiguation is also application-defined. A common pattern: 1. If the input exists as a local file, treat it as a path. 2. Else if gref parse succeeds, treat it as remote. 3. Else error. ## Security considerations - grefs can point at arbitrary public (or private) repositories. Tools that **execute** fetched content must treat it as untrusted code. - Prefer fixed refs (tags or commit SHAs) for reproducible installs; floating branches (`@main`) change over time. - Validate that resolved download URLs stay on the expected host before fetching. - Do not expand environment variables or shell metacharacters inside gref components. ## Versioning of this document This specification is versioned with semantic-style tags (`vMAJOR.MINOR.PATCH`): - **MAJOR** — incompatible grammar or meaning changes - **MINOR** — backward-compatible additions (new optional forms, hosts) - **PATCH** — clarifications, examples, non-normative text The latest published version is always available at [gref.sh](https://gref.sh). ## License This specification is available under the MIT License. See [license.txt](https://github.com/devlooped/gref/blob/main/license.txt).