Summary
A vcspull config cannot ask for a partial clone, so syncing a workspace of large repositories downloads every version of every file in their history. The git-only shallow and depth settings also sit in the VCS-neutral options: block, and editors have no schema to complete or check config files. Depends on partial clone support in libvcs, libvcs#553. Sized for one evening once that lands.
Problem
Prompt
Let a repo entry request a partial clone, give git-only settings their own block, and publish a JSON Schema for config files.
These must hold; everything after them is open:
- A repo entry can request a partial clone, and
vcspull sync produces one: remote.origin.partialclonefilter is set and history blobs are missing.
- A malformed filter, or an unknown key in the git-only block, fails when the config loads and names the file, workspace root, repository, and key; it never fails mid-sync.
- Existing configs keep loading. Older locations of
shallow and depth still work with a deprecation warning, and vcspull migrate rewrites them.
vcspull add and vcspull discover write the current layout.
- The vcspull runtime never imports pydantic, so CLI startup does not get slower.
- The published schema and the config loader accept and reject the same entries, enforced by a test.
Direction, non-binding:
- Add a top-level
git_options: {shallow, depth, filter} block on repo entries; rev stays in options:. filter takes git's spec string, a {kind: ..., <fields>} mapping, or a list of either, converted with libvcs coerce_filter and passed to GitSync as git_filter. git_options wins over options, which wins over top-level keys.
- Validate
git_options at load, reporting errors as '<workspace>' -> '<repo>' -> git_options.filter[<i>].
- Warn on
shallow/depth under options: and teach vcspull migrate both moves in one pass: top-level rev into options:, and shallow/depth from the top level or options: into git_options:. Also fix the existing deprecation warning, which joins the workspace key and repo name with no separator (~/codeflask).
- Make
build_repo_entry write git_options.
- Add
pydantic and jsonschema to the dev dependency group only. Add scripts/generate_schema.py to build the schema from the config TypedDicts, and commit its output under docs/_static/schemas/ so the docs site publishes it. Give the filter spec string a hint class that pydantic reads by method name, so no runtime import is needed, and have it validate with libvcs parse_filter. Test that the committed schema is current, and that shared fixtures give the same verdict through jsonschema against the schema file and through load_configs.
- Document
git_options, partial clones, and the # yaml-language-server: $schema=... comment; add a MIGRATION note; give the CHANGES entries YAML examples.
Target shape:
# yaml-language-server: $schema=https://vcspull.git-pull.com/_static/schemas/vcspull.schema.json
~/code/:
git:
repo: git+https://github.com/git/git.git
options:
rev: v2.55.0
git_options:
filter: blob:none
monorepo:
repo: git+https://github.com/example/monorepo.git
git_options:
depth: 50
filter:
- blob:limit=1m
- kind: tree
depth: 3
Details that cost time to rediscover:
- pydantic (repo, v2.13.5 release notes, PyPI) rejects
typing.TypedDict before Python 3.12, including TypedDicts imported from libvcs, so schema generator tests skip there. vcspull CI currently tests only Python 3.14.
- Validating at runtime with a pydantic
TypeAdapter built at import was tried and dropped: import vcspull.cli took about 220 ms instead of 120 to 133 ms (Python 3.14 free-threaded, best of 12 to 18 runs), and one bad filter produced several stacked errors naming pydantic internals, with no file path.
- In JSON Schema,
pattern and enum constrain strings only. Without "type": "string" on the string branch, a mapping such as {kind: nope} passes the filter union.
- The schema has to accept what vcspull writes:
url: in place of repo:, metadata from vcspull import --sync, and remotes as URL strings or {fetch_url, push_url} mappings, where the loader requires both keys.
- pydantic's
use_attribute_docstrings gives no descriptions for fields on TypedDicts split into Required and Optional bases, or on functional-syntax TypedDicts such as RepoPinDict.
- Validate the schema document itself with jsonschema (repo, v4.26.0 release notes, PyPI); asking pydantic again would miss every constraint the generator adds by hand.
- Differences the agreement test cannot cover yet:
combine containing auto passes the schema but fails at load; an empty filter list fails the schema but loads; a misspelled repo-entry key fails the schema but is ignored at load.
Not doing:
- Changing an existing checkout's filter on sync.
- Detecting an existing checkout's filter in
vcspull discover.
- Validating the whole config with pydantic at runtime.
Alternatives
Weighed and set aside:
options.filter next to shallow and depth: no migration, but git-only settings stay mixed into the VCS-neutral block.
- A nested
options.git: block migrated by vcspull fmt --write: splits migration across two commands, and fmt skips pinned entries, so those warn forever.
- Runtime pydantic validation: slower startup, broken on Python 3.10 and 3.11, and harder-to-read errors, as measured above.
References
Summary
A vcspull config cannot ask for a partial clone, so syncing a workspace of large repositories downloads every version of every file in their history. The git-only
shallowanddepthsettings also sit in the VCS-neutraloptions:block, and editors have no schema to complete or check config files. Depends on partial clone support in libvcs, libvcs#553. Sized for one evening once that lands.Problem
git clone --filter, which keeps full history while leaving out file contents until a command needs them.shallowanddepthonly apply to git but live inoptions:(https://github.com/vcs-python/vcspull/blob/v1.67.0/src/vcspull/types.py#L133-L190), next to VCS-neutralrevand pin policy, so a git-only filter key has no natural home there.vcspull addandvcspull discoverwrite entries throughbuild_repo_entry(https://github.com/vcs-python/vcspull/blob/v1.67.0/src/vcspull/config.py#L1061). Any new layout has to be written there too, or freshly added entries start out deprecated.Prompt
Let a repo entry request a partial clone, give git-only settings their own block, and publish a JSON Schema for config files.
These must hold; everything after them is open:
vcspull syncproduces one:remote.origin.partialclonefilteris set and history blobs are missing.shallowanddepthstill work with a deprecation warning, andvcspull migraterewrites them.vcspull addandvcspull discoverwrite the current layout.Direction, non-binding:
git_options: {shallow, depth, filter}block on repo entries;revstays inoptions:.filtertakes git's spec string, a{kind: ..., <fields>}mapping, or a list of either, converted with libvcscoerce_filterand passed toGitSyncasgit_filter.git_optionswins overoptions, which wins over top-level keys.git_optionsat load, reporting errors as'<workspace>' -> '<repo>' -> git_options.filter[<i>].shallow/depthunderoptions:and teachvcspull migrateboth moves in one pass: top-levelrevintooptions:, andshallow/depthfrom the top level oroptions:intogit_options:. Also fix the existing deprecation warning, which joins the workspace key and repo name with no separator (~/codeflask).build_repo_entrywritegit_options.pydanticandjsonschemato the dev dependency group only. Addscripts/generate_schema.pyto build the schema from the config TypedDicts, and commit its output underdocs/_static/schemas/so the docs site publishes it. Give the filter spec string a hint class that pydantic reads by method name, so no runtime import is needed, and have it validate with libvcsparse_filter. Test that the committed schema is current, and that shared fixtures give the same verdict throughjsonschemaagainst the schema file and throughload_configs.git_options, partial clones, and the# yaml-language-server: $schema=...comment; add a MIGRATION note; give the CHANGES entries YAML examples.Target shape:
Details that cost time to rediscover:
typing.TypedDictbefore Python 3.12, including TypedDicts imported from libvcs, so schema generator tests skip there. vcspull CI currently tests only Python 3.14.TypeAdapterbuilt at import was tried and dropped:import vcspull.clitook about 220 ms instead of 120 to 133 ms (Python 3.14 free-threaded, best of 12 to 18 runs), and one bad filter produced several stacked errors naming pydantic internals, with no file path.patternandenumconstrain strings only. Without"type": "string"on the string branch, a mapping such as{kind: nope}passes the filter union.url:in place ofrepo:,metadatafromvcspull import --sync, and remotes as URL strings or{fetch_url, push_url}mappings, where the loader requires both keys.use_attribute_docstringsgives no descriptions for fields on TypedDicts split into Required and Optional bases, or on functional-syntax TypedDicts such asRepoPinDict.combinecontainingautopasses the schema but fails at load; an empty filter list fails the schema but loads; a misspelled repo-entry key fails the schema but is ignored at load.Not doing:
vcspull discover.Alternatives
Weighed and set aside:
options.filternext toshallowanddepth: no migration, but git-only settings stay mixed into the VCS-neutral block.options.git:block migrated byvcspull fmt --write: splits migration across two commands, andfmtskips pinned entries, so those warn forever.References
$schemacomment