CLI Reference¶
Metaseed provides a command-line interface built with Typer.
Installation¶
The CLI is available after installing the package:
Command groups¶
Everything the MCP server and the web interface can do is reachable here too; Capability parity records which command serves which capability, and a test fails when the three surfaces drift apart.
| Group | What it covers |
|---|---|
metaseed dataset |
The saved datasets: list, show, create, delete, import, export, validate |
metaseed entity |
The entities inside one dataset: list, show, tree, create, update, delete, bulk-update, batch-create |
metaseed profile |
What a profile defines: schema, relationships, fields, required, field |
metaseed ontology |
Terms: search, term, suggest, list, validate |
metaseed extract |
Reading metadata out of files: parse, analyze, run, validate, export |
metaseed spec |
Authoring a profile: create, clone, import, status, preview, validate, save, and the entity/field/rule editing commands |
metaseed seek |
FAIRDOM-SEEK: check, preview, provision, sync, isa-rdf, isa-templates, model-ttl, import-templates |
metaseed hub |
metaseed-hub: check, list, collaborations, push-dataset, pull-dataset, profiles, push-profile, pull-profile |
metaseed plugin |
The optional adapters: list, enable, disable, config, check |
metaseed dcat |
Catalogue records: show, set |
Each group prints its own help: metaseed dataset --help.
How a dataset command works¶
The web interface and the MCP server act on one editing session; the command line has none, so every command names the dataset it acts on, loads it, changes it and writes it back:
metaseed dataset create test-drought --profile isa --version 1.0
metaseed entity create test-drought Investigation --set identifier=I1 --set title="Drought trial"
metaseed entity list test-drought
metaseed dataset validate test-drought
--set name=value is repeatable, and a value that parses as JSON is kept as
JSON, so --set comments='[{"name":"a","value":"b"}]' sets a list.
Output is JSON, so a script reads what a person reads:
Authoring a specification¶
A draft is a file rather than a session:
metaseed spec create draft.yaml --name my-profile --version 1.0
metaseed spec add-entity draft.yaml Study
metaseed spec add-field draft.yaml Study identifier --type string --set required=true --set is_identifier=true
metaseed spec set-root draft.yaml Study
metaseed spec validate draft.yaml
metaseed spec save draft.yaml
Pushing to a hub¶
metaseed plugin config hub --set url=https://hub.example.org --set token=msh_...
metaseed hub check
metaseed hub push-dataset test-drought --plan # what would happen
metaseed hub push-dataset test-drought # do it
metaseed hub list
A hub dataset of the same name that differs is not replaced unless --replace
is given, and a pulled dataset never overwrites a differing local one.
Commands¶
version¶
Show the package version:
entities¶
List available MIAPPE entities for a version:
validate¶
Validate a metadata file:
When the profile's adapter registers validate actions, they run after the
entity validation: --profile pride also applies the ProteomeXchange
submission rules (mandatory MTD fields, RAW/RESULT/SEARCH file mapping) and
resolves CV terms; --profile metabolights resolves its CV terms. Their
findings count toward the exit code like any other validation error.
template¶
Generate an empty template for an entity:
Options:
| Option | Description |
|---|---|
--output, -o |
Output file path (prints to stdout if not specified) |
--format, -f |
Output format: yaml (default) or json |
--version, -v |
MIAPPE version (default: 1.1) |
convert¶
Convert between YAML and JSON formats:
The format is determined by file extension (.yaml, .yml, or .json).
ui¶
Launch the web interface:
Options:
| Option | Description |
|---|---|
--host, -h |
Host to bind to (default: 127.0.0.1) |
--port, -p |
Port to bind to (default: 8080) |
The web interface provides:
- Visual entity browser organized by hierarchy
- Dynamic forms generated from YAML specifications
- Nested entity creation (e.g., add Studies to an Investigation)
- Validation feedback
- Support for both MIAPPE and ISA profiles
profiles¶
List available profiles and their versions:
Output shows all installed profiles (miappe, isa, seek, darwin-core, dissco, ena, etc.) with their available versions.
compare¶
Compare multiple profile specifications to see differences in entities, fields, and constraints:
# Compare two profiles (outputs markdown to stdout)
metaseed compare miappe/1.1 isa/1.0
# Compare with output file
metaseed compare miappe/1.1 isa/1.0 -o comparison.md
# Different output formats
metaseed compare miappe/1.1 isa/1.0 -f csv -o comparison.csv
metaseed compare miappe/1.1 isa/1.0 -f html -o comparison.html
# Compare multiple profiles
metaseed compare miappe/1.1 isa/1.0 seek/1.0
Options:
| Option | Description |
|---|---|
--output, -o |
Output file path (prints to stdout if not specified) |
--format, -f |
Output format: markdown (default), csv, or html |
The comparison report shows:
- Summary statistics (total entities, common, unique, modified, conflicts)
- Entity-by-entity comparison with presence indicators
- Field-level differences including type changes and constraint modifications
merge¶
Merge multiple profile specifications into a single combined profile:
# Basic merge (uses first_wins strategy)
metaseed merge miappe/1.1 isa/1.0 -o combined.yaml
# Merge with specific strategy
metaseed merge miappe/1.1 seek/1.0 -s most_restrictive -o strict.yaml
# Custom name and version
metaseed merge miappe/1.1 isa/1.0 -n my-profile -v 2.0 -o my-profile.yaml
Options:
| Option | Description |
|---|---|
--output, -o |
Output YAML file path (default: merged.yaml) |
--strategy, -s |
Merge strategy (default: first_wins) |
--name, -n |
Name for the merged profile |
--version, -v |
Version for the merged profile (default: 1.0) |
Available merge strategies:
| Strategy | Behavior |
|---|---|
first_wins |
Use the first profile's value for conflicts |
last_wins |
Use the last profile's value for conflicts |
most_restrictive |
required=True wins, tighter constraints |
least_restrictive |
required=False wins, looser constraints |
prefer_<profile> |
Always prefer a specific profile (e.g., prefer_miappe/1.1) |
check¶
Validate a dataset with cross-entity reference-integrity checking (stricter than
validate, which checks a single entity).
example¶
Export the example dataset bundled with a profile.
mcp¶
Start the MCP (Model Context Protocol) server, exposing metaseed's tools to an MCP client.
migrate¶
Migrate stored datasets to use unique_id for entity references.
migrate-specs¶
Repair profile specs whose version is not MAJOR.MINOR. Since 0.22 a version that does not match ^\d+\.\d+$ is rejected on load (see Profile Versioning), so a spec written by an earlier release is listed but cannot be loaded. This command finds those files and rewrites the offending value.
# Report what would change; writes nothing (default)
metaseed migrate-specs
# Write the changes
metaseed migrate-specs --apply
Both the built-in specs directory and the user specs directory (~/.local/share/metaseed/specs/) are scanned.
Normalization rules¶
The rules combine: in v1.2.3-rc1 the v is stripped, the -rc1 suffix dropped and the third component truncated, giving 1.2 (LOSSY).
Stored version |
Rule | Result |
|---|---|---|
'1.2' |
already MAJOR.MINOR |
unchanged, not reported as a change |
v1.2 |
a leading v is not part of the version |
'1.2' |
1 |
a single integer names a MAJOR only; MINOR is 0 |
'1.0' |
1.2-dev-a1b2c3, 1.2-rc1, 1.2+build.5 |
a pre-release or build suffix is not a profile version component | '1.2' |
1.2.3 |
only two components exist; the rest is discarded | '1.2', reported LOSSY |
1.0 unquoted |
YAML reads it as a number, and version is a string |
'1.0' |
draft, latest, `` (empty) |
no leading integer, so no version is derivable | unchanged, reported NEEDS MANUAL FIX |
The value is always written quoted, which is also what SpecBuilder.to_yaml() produces. That is what the unquoted-number row is about: version: 1 is an integer to YAML and version: 1.0 a float, and a version that is not a string fails to load for that reason alone, digits notwithstanding.
1.2.3 -> 1.2 is flagged LOSSY because the patch component is discarded: two files that differed only in patch normalize to the same version, and nothing records which was which. A value with no leading integer is never guessed — the file is left alone and the report names it, its path, and the rule it failed.
What is written¶
Only the version: value is rewritten. The rest of the file — key order, comments, quoting, blank lines — is left byte-for-byte as it was, so a hand-maintained spec survives the migration unchanged apart from that one value.
A spec's version is also its directory name (specs/<name>/<version>/profile.yaml), and metaseed profiles and the loader address a spec by that directory name. When the directory name is the same non-conforming string as the file's version, it is renamed alongside the value, so the repaired spec is addressable by the version it declares. When the directory name and the declared version already disagree, the directory is left alone and the report notes the mismatch; renaming it would change the version users address the spec by.
A saved dataset records the profile version it was created against, and that reference is not rewritten here. After a rename, edit the version field of any dataset naming the old string — the report says so whenever it renames anything.
Collisions¶
A rename is refused, not resolved, when it would put two specs at the same <name>/<version> path: two directories normalizing to the same target (cinema/1.2-rc1 and cinema/1.2-dev-a1b2c3 both become cinema/1.2), or a target directory that already exists. Both files are reported as COLLISION with the target path and are left untouched, including their version: value — a partial repair would leave two specs claiming one identity, which is the state a published profile identity must not silently reach. Resolve it by choosing distinct versions by hand and re-running.
A repair that leaves two specs declaring the same name and version without sharing a path — repairing cinema/0.9 to declare 1.2 while cinema/1.2 exists — is carried out but noted in the report. Nothing is overwritten and both stay addressable by their own directory, and two specs may legitimately declare one version and differ in content; content_hash is what distinguishes them. The note is there so the duplication is not something you discover later.
Report and exit code¶
One entry per non-conforming spec — its path, the old version, either the new version or the reason no repair was made, and any directory rename — then a summary counting the non-conforming specs, those repaired (WOULD REPAIR in a dry run), and those lossy, colliding or needing a manual fix. Conforming specs are not listed. Each entry is labelled:
| Label | Meaning |
|---|---|
[WOULD REPAIR] / [REPAIRED] |
the version was normalized; the two words distinguish a dry run from a write |
[LOSSY] |
added to a repair that discarded a patch component |
[NEEDS MANUAL FIX] |
no version derivable, or the value is not on a top-level version: line and so cannot be replaced without reformatting; file untouched |
[COLLISION] |
repair refused to avoid two specs at one name+version |
[ERROR] |
the file could not be read, parsed, or written |
| Situation | --apply exit code |
|---|---|
| Nothing to do, or every non-conforming spec repaired | 0 |
| Specs reported NEEDS MANUAL FIX or LOSSY | 0 — findings, not failures |
| A repair was attempted and did not complete: a refused collision, or a filesystem error | 1 |
A dry run always exits 0; it reports, it does not judge.
Global Options¶
| Option | Description |
|---|---|
--version |
Show version and exit |
--help |
Show help message and exit |
Configuration¶
The CLI reads configuration from:
- Command-line arguments
- Environment variables (prefixed with
METASEED_) - Configuration file (
metaseed.yamlin current directory)