Metagit Development Guide#
Upon making changes run the following to validate everything before submitting a PR
task format lint:fix test
MCP Development Notes#
- Use
metagit mcp serveto start the MCP stdio runtime. - Use
--root <path>to test workspace gating against a specific folder. - Use
--status-oncefor quick diagnostics without starting the message loop. - MCP gating states:
inactive_missing_configwhen.metagit.ymlis not presentinactive_invalid_configwhen.metagit.ymlfails validationactivewhen.metagit.ymlloads successfully
Provider Source Sync#
Use source sync to discover repositories from GitHub/GitLab and plan/apply workspace updates:
- Discover-only:
metagit project source sync --provider github --org <org> --mode discover - Additive apply:
metagit project source sync --provider github --org <org> --mode additive --apply - Idempotent additive (CI-safe):
metagit project source sync --provider github --org <org> --mode additive --ensure --apply - Refresh metadata with ensure: add
--refresh-metadatato update descriptions/tags on existing URLs - Filters: repeatable
--ignore '**/deprecated/**'and--include-pattern 'acme/platform-*' - Agent JSON: append
--json(logs stay on stderr when not using JSON-only tooling) - Clone after apply:
--syncrunsmetagit project syncfor the target project - Agent alias:
metagit workspace import --project <p> --provider github --org <org> [--ignore ...] - MCP (ACTIVE):
metagit_project_source_syncwith the same parameters (apply,confirm,sync) - Reconcile apply:
metagit project source sync --provider gitlab --group <group> --mode reconcile --apply --yes
Declarative sources[] (manifest sync)#
Store import scopes on workspace.projects[].sources[] and sync from the manifest instead of CLI flags:
workspace:
projects:
- name: platform
sources:
- id: github-platform
provider: github
org: acme
mode: additive
ensure: true
ignore:
- "**/archived/**"
repos: []
- Manifest sync:
metagit project --project platform source sync --from-manifest --apply --json - Single source:
--source-id github-platform - Persist imperative flags:
--write-source --source-id github-platform(after a successful imperative sync) - Project sync hook:
metagit project sync --project platform --refresh-sources(manifest sync then git sync) - Reconcile removals are deferred unless
--force; pending removals enqueuesource_sync_reconcileapprovals — approve withmetagit context approval approve --id <id> - Repos without
source_idare manual entries and are never auto-removed during reconcile
Web: Config Studio edits sources[]; Workspace Console Operations panel runs manifest sync and resolves approvals. See metagit-web.md.
Modality parity#
Operator-facing features should share core services across CLI, MCP, and web. When adding capability:
- Put logic in
src/metagit/core/…(not in Click handlers or React alone). - Wire adapters for each modality in the same change when possible.
- Register markers in
scripts/modality-parity.yml;task qa:prepushrunsscripts/check_modality_parity.py. - Follow
.mex/patterns/modality-parity.md.
GitHub org/user listing is flat (no nested subgroups). GitLab groups honor --recursive / --no-recursive for subgroups. Default manifest naming is namespaced; use --name-strategy short for legacy short names.
| Flag combo | Re-run behavior |
|---|---|
--mode additive --apply |
Add missing; update changed metadata |
--mode additive --apply --ensure |
Add missing; noop for existing URLs |
--ensure --refresh-metadata |
Ensure plus provider metadata refresh |
Repo Locator Migration Policy#
Workspace repo entries must use exactly one locator: path or url.
Use this policy when deciding whether path-based entries should be promoted to git-managed clones.
Keep as path-based#
- local sandboxes or one-off experiments
- generated/vendor directories without stable git remotes
- machine-specific paths that are intentionally not shared
Promote to git-managed (url)#
- shared codebases used by multiple contributors or agents
- repos expected to run in CI or cross-machine workflows
- entries with stable remotes and reproducibility requirements
Migration workflow#
- Inventory path-based entries in target projects.
- Classify each entry as local-only or shared.
- Dry-run promotion first:
metagit project --project <project_name> repo promote --name <repo_name> --dry-run
- Execute promotion (use explicit
--urlwhen origin is missing/nonstandard):
metagit project --project <project_name> repo promote --name <repo_name>
metagit project --project <project_name> repo promote --name <repo_name> --url <git-url>
- Validate and sync state:
metagit config validate --config-path .metagit.yml
metagit project sync --project <project_name>
metagit project repo list --project <project_name> --json
Common promotion failures#
protected: repo/project is protected; rerun with--forceonly when approved.source_missing: configured path does not exist on disk.no_url: no explicit URL and no usable git remote discovered.invalid_url: URL failed git URL validation.duplicate_identity: same remote identity already exists elsewhere in workspace.sync_failed: manifest update succeeded but clone/sync failed; investigate workspace sync logs.
Changelog and releases#
- Maintain user-facing changes under
## Unreleasedin rootCHANGELOG.md. task qa:prepushand CI runscripts/validate_changelog.pywhensrc/,schemas/, orweb/change. SetSKIP_CHANGELOG_CHECK=1to bypass locally.- The docs site publishes the same file at
/changelog/—task docsand the docs workflow syncCHANGELOG.mdintodocs/changelog.mdbeforemkdocs build.
Semantic Release Tags#
.github/workflows/semantic-release.yaml runs on merges to main and uses conventional commit prefixes to compute the next version.
- Promotes
## Unreleasedinto a dated version section inCHANGELOG.md, commits tomain, then tags. - Tags created by the workflow use the canonical
vX.Y.Zformat. - GitHub Release notes use the promoted changelog body (commit-log fallback only when
Unreleasedis empty). - Changelog-only commits do not retrigger semantic release, and no tag is created when there are no releasable
fix:,feat:, or breaking-change commits since the previous tag. - The workflow currently floors computed release versions at
0.8.0so the next valid release lands onv0.8.0or newer instead of continuing the accidental0.7.xline. -
Release automation is deterministic (no LLM). GitHub Copilot AI credits are not a free pipeline for custom workflows; they meter Copilot Chat/agents/review features instead.
-
fix:-> patch release (X.Y.Z+1) default for most updates feat:-> minor release (X.Y+1.0)type(scope)!:orBREAKING CHANGE:-> major release (X+1.0.0)
Commit Prefix Guidance#
Use patch semantics first (fix:) unless schema/config compatibility is intentionally broken.
- Use
fix:for normal maintenance and safe behavior changes. - Use
feat:only for additive, backward-compatible functionality. - Use
!/BREAKING CHANGEwhen changing.metagit.ymlor app config schema in a non-backward-compatible way.