Publishing¶
lcp publish submits an LCP manifest to the central registry (or your own registry repo) by opening a Pull Request with the manifest and structured metadata.
How publishing works¶
Publishing uses a fork-and-PR flow against the central registry at zazza123/lcp-registry (the value of _DEFAULT_REGISTRY_REPO in src/lcp/publish.py). When you run lcp publish, the command authenticates with GitHub, forks the registry repo into your account if a fork does not already exist, creates a branch named lcp/add/<package>/<version>, gzip-compresses the manifest, and pushes it to the correct sharded path on that branch. It then opens a pull request against the upstream main branch with a structured body listing package metadata and a checklist.
A GitHub personal access token is required. The token must have the repo scope (for private registries) or public_repo scope (for the public registry). You can supply it via the --token flag or by setting the LCP_GITHUB_TOKEN (or GITHUB_TOKEN) environment variable. The tool does not store credentials; it passes the token directly to the GitHub API for each request.
Quick start¶
On success, lcp publish prints the URL of the newly opened pull request. If authentication fails, the command exits with a clear error message indicating the required token scope. Publishing is not fully idempotent at the GitHub level — if a branch for the same (package, version) tuple already exists on your fork, the command will fail with a GitHub API error rather than silently overwriting it.
CLI flags¶
| Flag | Default | Description |
|---|---|---|
PACKAGE |
(required) | Importable name of the installed Python package to publish. |
--token |
LCP_GITHUB_TOKEN env |
GitHub personal access token with repo or public_repo scope. Also reads GITHUB_TOKEN. |
--registry-repo |
zazza123/lcp-registry |
Target registry repository in owner/name format. |
--file |
(none) | Path to an existing .lcp.json file; skips scanning. |
--include-private |
off | Include private symbols (names starting with _) in the manifest. |
--no-recursive |
off | Skip submodule scanning; only scan the top-level package. |
--dry-run |
off | Generate the manifest and show what would be submitted without creating a PR. |
Example:
Publishing to a private registry¶
Pass --registry-repo owner/repo to target a different registry. This is useful for organizations that maintain an internal registry alongside or instead of the public one.
For private registries, the token must have full repo scope so the command can fork, push to, and open PRs against a private repository. For the public registry, public_repo scope is sufficient.
Registry layout¶
Manifests are stored in a sharded directory structure that keeps directory sizes manageable and reduces merge conflicts when many packages are submitted in parallel. Each manifest is gzip-compressed (typically a ~70% size reduction).
lcp-registry/
├── manifests/
│ └── python/
│ ├── f/
│ │ └── flask/
│ │ └── 3.0.0.lcp.json.gz
│ ├── n/
│ │ └── numpy/
│ │ ├── 1.26.0.lcp.json.gz
│ │ └── 2.0.0.lcp.json.gz
│ └── r/
│ └── requests/
│ └── 2.31.0.lcp.json.gz
└── README.md
The path template is:
For example, requests version 2.31.0 lands at manifests/python/r/requests/2.31.0.lcp.json.gz. The first-letter shard (r/) prevents any single directory from accumulating thousands of entries.
Programmatic usage¶
from lcp import scan
from lcp.publish import publish_manifest
doc = scan("requests")
result = publish_manifest(
doc,
token="ghp_...",
registry_repo="zazza123/lcp-registry", # optional, this is the default
)
print(result.pr_url) # https://github.com/zazza123/lcp-registry/pull/<n>
print(result.manifest_path) # manifests/python/r/requests/2.31.0.lcp.json.gz
publish_manifest(document, token, registry_repo=...) accepts a validated LCPDocument, a GitHub token string, and an optional registry_repo argument (default: "zazza123/lcp-registry"). It returns a PublishResult dataclass with fields pr_url, pr_number, manifest_path, package_name, package_version, and language. On failure it raises PublishError (for GitHub API, network, or permission errors) or ValueError (for a malformed registry_repo string).
See also¶
- CLI reference — full flag list.