# CLI surface This document describes the intended command-line interface at the project level. ## Core commands ### Set a value ```bash git meta set ``` `git meta set` always writes a string value. List and set values are mutated through their own dedicated verbs (see below). Examples: ```bash git meta set commit:314e7f0fa7 agent:model claude-4.6 git meta set path:src/metrics review:status approved ``` ### Get values ```bash git meta get [] ``` Behavior: - with only ``, show all keys for the target - with ` `, show the exact key if present - with ` `, show matching subkeys ### Remove a key ```bash git meta rm ``` This removes the logical key and records a whole-key tombstone. ## List operations ```bash git meta list:push git meta list:pop ``` Notes: - `list:push` appends a new list entry - `list:pop` requires explicit exchange semantics before implementation is finalized; see [Lists](../exchange-format/lists.md) - if a string key is pushed to as a list, the implementation may convert it to a list ## Set operations ```bash git meta set:add git meta set:rm ``` Notes: - `set:add` creates the set if it does not already exist - `set:add` is idempotent for an existing member - `set:rm` removes a single member and records a member tombstone ## Exchange commands ### Serialize ```bash git meta serialize [--force-full] ``` Writes a new metadata commit for the current local shareable state. By default this may use incremental dirty-target detection. `--force-full` rebuilds the serialized tree from the complete local SQLite state. ### Materialize ```bash git meta materialize [] ``` Behavior: - if `` is given, materialize from that remote metadata ref - if omitted, inspect all known metadata remotes and materialize them ### Dry-run materialize ```bash git meta materialize --dry-run [] ``` Useful for reporting the merge strategy and conflict decisions without applying them. ## Sync commands `push`, `pull`, and `sync` are the porcelain that bundle a local serialize/materialize with the network step against a configured metadata remote. They are the commands a project uses day-to-day; `serialize` and `materialize` are the underlying plumbing. ### Push ```bash git meta push [] git meta push [] --readme ``` Behavior: - serializes any pending local metadata changes (equivalent to `git meta serialize`) and pushes the resulting metadata commit on `refs//main` to the named remote - if `` is omitted, the first configured metadata remote is used - `--readme` instead pushes a starter `README.md` commit to `refs/heads/main` on the metadata remote, and only if that branch does not already exist (no force push). This is purely cosmetic — it gives the metadata repository something human-readable when browsed on the forge — and is independent of the metadata refs themselves ### Pull ```bash git meta pull [] ``` Behavior: - fetches `refs//main` from the remote into that remote's configured tracking ref and runs the equivalent of `git meta materialize` to merge the new history into the local SQLite database - primary metadata remotes track `refs//remotes/main`; side metadata remotes track `refs//remotes//main` - if `` is omitted, a primary configured metadata remote is used in preference to side remotes - prints `Already up-to-date.` when the remote tip is unchanged ### Sync ```bash git meta sync [] ``` Behavior: - pulls remote metadata first, which fetches `refs//main`, serializes local metadata for merge, and materializes remote changes into the local SQLite database - pushes the merged local metadata afterward, serializing again and pushing `refs//local/main` to `refs//main` - if the push is rejected because the remote advanced, fetches and materializes the new remote state, reserializes locally, rewrites the local metadata commit on top of the remote tip, and retries - if `` is omitted, all configured metadata remotes are pulled first and then all configured metadata remotes are pushed ## Setup and configuration These commands wire a project up to a metadata remote, or undo that wiring. They never write or read metadata values directly; they only manage the local state needed by the sync and exchange commands above. ### Setup ```bash git meta setup ``` Initializes a metadata remote for the current repository from a project-local `.git-meta` file at the repository root. The file is YAML with a required `url` key: ```yaml url: git@github.com:org/project-meta.git ``` Unknown keys are ignored, so future versions can add more project-local setup fields without breaking older clients. Behavior: - reads `.git-meta` from the repository work tree - runs the equivalent of `git meta remote add --init`, so on a fresh metadata remote the command will also create `refs//local/main` with a starter README and push it to `refs//main` - intended to be the one command a teammate runs after cloning to opt in to the project's metadata exchange ### Add a remote ```bash git meta remote add [--name ] [--namespace ] [--init] ``` Configures a new metadata remote for the current repository. Behavior: - writes git config entries for the remote: `remote..url`, `remote..fetch`, `remote..meta = true`, plus partial-clone/promisor settings so blobs are fetched on demand - the first metadata remote is primary and fetches to `refs//remotes/main`; if a primary metadata remote already exists, the new remote is marked with `remote..metaside = true` and fetches to `refs//remotes//main` - inspects the remote with `git ls-remote` to check that `refs//main` exists, and on success runs an initial blobless fetch and `materialize` so values are immediately readable - if no metadata refs are present on the remote: - with `--init`, creates (or reuses) `refs//local/main` with a starter README commit and pushes it to `refs//main` on the remote - on an interactive terminal without `--init`, prompts the user for confirmation and behaves as if `--init` had been passed when they accept - in non-interactive contexts (CI, pipes), bails with an actionable hint to re-run with `--init` - if metadata refs are found under a different namespace, bails with a hint to re-run with `--namespace=` Defaults: - `--name`: `meta` - `--namespace`: from the `meta.namespace` git config, falling back to `meta` The companion verbs `git meta remote list` and `git meta remote remove ` are also available for inspecting and removing configured metadata remotes. ### Teardown ```bash git meta teardown ``` Removes the local git meta state from the repository. Behavior: - deletes the SQLite database at `.git/git-meta.sqlite` - deletes every reference under `refs//`, including local, serialized, and remote-tracking refs This does **not** touch any remote, and is intended for cases like switching namespaces, recovering from local corruption, or cleanly uninstalling git meta from a checkout. After teardown, `git meta setup` (or `git meta remote add`) re-installs the local state. ## Target syntax Targets use the syntax documented in [Targets and keys](../exchange-format/targets.md). Examples: ```bash commit: change-id: branch: path:src/metrics project ``` ## Value encoding `git meta set` only writes string values. To populate or mutate list and set values, use the dedicated verbs: - `git meta list:push ` to append a list entry - `git meta list:pop ` to drop a list entry - `git meta set:add ` to add a set member - `git meta set:rm ` to remove a set member ## Output modes `git meta get` may support: - human-readable tabular output - `--json` - `--with-authorship` for author/timestamp metadata in JSON mode The output model is documented in [Output](./output.md).