use-cmeta-cli
Skill9 starsChanged 11 days agoApache-2.0View on GitHub
Use cMeta from the command line (`cx` / `cmeta` / `cxt` / `cxai` / `cserver`) — argument model, discovery flow, global flags, output modes, aliases, `.` current-directory shortcut, `@file` includes, ctx-through-CLI patterns, and script-friendly conventions. Portable — same recipes work in any repo that ships cMeta categories/artifacts.
In this repository8 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- llms.txtllms.txt
- add-cserver-pluginSkill
- add-pluginSkill
- add-repoSkill
- release-cmetaSkill
- use-cmeta-pythonSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 26
All entry points call the same dispatch — they just prepend arguments.
- Very specific: line 55
Every category also ships two built-in demo commands: test <arg> and test2 <arg> — safe to try.
- Very specific: line 200
Prefer find as the universal lister — unlike a bare ls it also prunes by tags/filters, so it works as list, ls and find in one.
- Very specific: line 377
Keep --reindex for the broad cases: a wiped CMETA_HOME, a bulk change across repositories, or an index that looks generally wrong.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
use-cmeta-cli — using cMeta from the command line
Reusable across repos. These recipes describe the CLI surface of cMeta itself — they don't depend on any particular content repo.
cx --helpandcx <category> <command> --helpare the ultimate authorities.
1. Entry points
Shipped by pyproject.toml [project.scripts]:
| Command | Purpose |
cx | Short-hand for cmeta. Most common. |
cmeta | Full name — same as cx. |
meta | Alias of cmeta. |
cxt | Shortcut for cx task run …. |
cxai | Shortcut for cx task run run-ai … (every argument goes to run-ai unchanged). |
cserver | Shortcut for cx app run cserver … (local FastAPI UI). |
ucx / ucmeta / umeta / ucxt / ucxai / ucserver | "u" variants — force --home (unbuffered / alt HOME). |
All entry points call the same dispatch — they just prepend arguments.
2. Invocation model
cx [<category>] [<command>] [<arg1> <arg2> ...] [--flag ...] [--k=v ...] [-- passthrough]- The 1st positional token is
<category>. - The 2nd is
<command>(or a command alias — see §6). - Remaining positional tokens become
arg1,arg2,arg3, ... on the call. - Flags (
--k,--k=v,-k) can appear in any order. - Everything after a lone
--is stored inunparsed(rarely needed; use to pass args verbatim to sub-processes likecx app run <a> -- --foo).
Special first token: . — auto-detect the artifact under the current
directory (see §7).
3. Discovery — how to explore without reading source
cx --help # framework help + all global flags
cx category list # every category (plugin) known to cMeta
cx <category> --help # commands available in a category
cx <category> <command> --help # per-command args/flags
cx repo list # every registered content repository
cx --version # cMeta version + check for updateEvery category also ships two built-in demo commands: test <arg> and
test2 <arg> — safe to try; they just echo the parsed params.
4. Global flags (from cmeta/config.py)
Full reference: docs/using-cmeta.md §3. Highest-signal subset:
| Flag | Meaning |
--help, -h | Framework/category/command help. |
--version, -V | Version + update check. |
--reindex | Rebuild <CMETA_HOME>/index/*.pkl. Fix stale lookups. |
--verbose, -v | Extra progress info. |
--quiet, -q | Auto-accept default answer to prompts (script-safe). |
--repro, -r | Save call inputs/outputs (cmeta-repro-*.json). |
--base | Force the shared base command instead of a category override. |
--api <n> | Pin category API version. |
--con | Force console output (default for CLI; needed for library calls). |
--json, -j | Print return dict as JSON. |
--json_file <p>, --jf | Also write JSON to a file. |
--dump | Dump full call ctx to cmeta-ctx.json. |
--home <path> | One-shot <CMETA_HOME> override. |
--debug | --log_level=DEBUG + --fail_on_error. |
--fail, --fail_on_error | Raise on first error instead of returning. |
--log_level <lvl>, --log_file <p> | Standard logging knobs. |
--pause_if_error, --pif | Pause before exiting on error (double-click friendly). |
Hyphen and underscore forms are equivalent (--log-level == --log_level).
5. Flag syntax cheatsheet
Parsed by cmeta/utils/cli.py::parse_cmd. Rules:
| Syntax | Result |
--key | boolean True |
--key- | boolean False |
--key=yes / --key=no | boolean when the command annotates key: bool (also true/false, on/off, 1/0); any other word is an error; text for a parameter without the annotation |
--no-key | boolean False |
--key=value | string / int (repeats overwrite — last wins); --key value is the flag --key (True) + a positional value |
--key,=v1,v2,v3 | list [v1, v2, v3] (trailing comma on the key requests split) |
--key,= | empty list [] |
--parent.child=v | nested dict {'parent': {'child': v}} |
key=value (no dashes) | same as --key=value when the part before = looks like a key (a letter or _, then letters, digits, _ . , -); other text with = ("echo a=b", a URL with a query) is positional |
-5, -1.5 | positional (a negative number is not a flag) |
@somefile.yaml | inline the YAML/JSON file as flags (deep-merged) |
@@somefile.yaml | same, then delete the file |
-- | everything after → unparsed list, for the commands that read it (others say "takes no arguments after --") |
| bare token | positional → arg1, arg2, ... |
Examples:
# Nested meta from CLI:
cx experiment add e1 --meta.description="pilot run" --meta.hw.gpu=A100
# Tasks (the task engine in cmeta-aops): reach ANY sub-task of a run by its storage key,
# e.g. the Python some deep dependency sets up, or a control switch of one step:
cxt <task> --use.python.version=3.12.13
cxt <task> --use.<storage key>.update
# (keys and rules: cmeta-aops docs/cmeta-aops/task-engine.md, "Changing a dependency anywhere in a pipeline")
# List value (base commands split on ',' automatically for tags):
cx repo find --tags=demo,gpu
# Explicit list (works for any flag, not just tags):
cx <cat> <cmd> --files,=a.txt,b.txt,c.txt
# Positional arg + flag mix:
cx repo checkout my-repo main --verbose
# Load params from a file (see §5.1 below):
cx category add --debug @create-args.yaml5.1 @input.yaml / @input.json — reusable parameter files
Any positional token starting with @ is treated as a YAML or JSON file
whose contents are deep-merged into the parsed params. Great for capturing
long invocations, sharing recipes with a team, or driving repeated runs from
CI:
cx category add @create-args.yaml
cx experiment run e1 @run-config.json
cx <cat> <cmd> @@one-shot.yaml # `@@` also deletes the file after readingFormat is auto-detected from the extension (.yaml, .yml, .json).
Example run-config.json:
{
"meta": {"description": "pilot run", "hw": {"gpu": "A100"}},
"verbose": true,
"ctx": {"agent": {"session": "sess-42"}}
}You can mix multiple @file inclusions and regular flags on the same command
— later values (further right on the command line) override earlier ones. On
Windows, quote paths containing backslashes so shlex.split doesn't mangle
them: cx <cat> <cmd> @"C:\path\to\file.yaml".
Use cases:
- Team recipes — commit a
run-experiment.yamlin your repo and sharecx experiment run @run-experiment.yaml. - CI matrices — generate per-row JSON files and fire
cx <cat> <cmd> @row.json. - Agent hand-off — an agent writes a
@@call.yamland invokes cMeta once with all its assembled state; the@@auto-cleans the temp file.
6. Command aliases (built-in)
Global (from cmeta/config.py) — work on any category:
| Alias | Real command |
add | create |
rm, remove, del | delete |
ren, rename, mv | move |
cp | copy |
ls | list |
search | find |
load | read |
Per-category aliases live under command_aliases: in a category's _cmeta.yaml.
7. Current-directory shortcut (cx .)
cx . inspects the current working directory, walks up to find the enclosing
repo (_cmr.yaml), then the enclosing category and — if present — the enclosing
artifact (_cmeta.yaml), and injects the matching repo + category (+ artifact)
so you don't type them.
Inside a category directory — category + repo are inferred, the command still takes an artifact arg:
cd /path/to/some/repo/log
cx . add xyz # → cx log add <repo>:xyz
cx . find # → cx log find <repo>: (list this category/repo)
cx . find --tags=demo # ...pruned by tagsPrefer find as the universal lister — unlike a bare ls it also prunes by
tags/filters, so it works as list, ls and find in one.
Inside an artifact directory — the artifact is the target, no category or artifact ref needed:
cd /path/to/some/repo/experiment/e1
cx . load # → cx experiment load e1 (print its meta)
cx . update --meta.description="..." # update this artifact
cx . info # → cx experiment info e1
cx . # info is the default when . resolves to an artifact
cx . <cat> <command> # pass an explicit category to override detectionSame detection is available programmatically via
cm.utils.common.detect_cid_in_the_current_directory(cm).
8. Output modes for scripts and agents
Machine-readable stdout:
cx repo list --json # print JSON return dict to stdout
cx <cat> read <alias> -j # same, short form
cx <cat> find <alias> --jf=out.json # ALSO write JSON to file
cx <cat> find <alias> --json --json_file=out.jsonMuffle output when scripting:
cx <cat> <cmd> ... --quiet # auto-accept prompts
cx <cat> <cmd> ... --con- # suppress the default console outputFull call context for downstream tooling:
cx <cat> <cmd> ... --dump # writes cmeta-ctx.json (ctx after call)
cx <cat> <cmd> ... --repro # writes cmeta-repro-input.json + -output.jsonExit codes: 0 on success, non-zero equals the returned return code
(useful in Makefile / CI).
9. Passing ctx (context) from the CLI — good for AI agents
ctx is a dict that the framework threads through every nested access()
call. It carries framework-owned keys (see the Python skill §5) plus anything
you attach yourself. CLI flags can seed the initial ctx via
--ctx.<key>[.<child>]=<value> (parsed as a nested dict):
# Attach agent metadata that any hook in the call tree can read:
cx experiment run e1 \
--ctx.agent.session_id=sess-42 \
--ctx.agent.trace_id=trace-abc \
--ctx.agent.budget_tokens=20000
# Or load from a file:
cx experiment run e1 @agent-ctx.yamlGuidelines when using ctx from the CLI:
- Namespace your keys (
--ctx.agent.*,--ctx.trace.*) — never overwrite framework keys (origin,nested_call,control,command,category*,category_artifact,last_self_time,repro). - Combine with
--dumpto capture the post-call ctx (with any state a hook wrote back) intocmeta-ctx.json. - ctx is shared across nested calls — a hook can mutate it and later hooks see the update.
10. Working recipes
10.1 Everyday exploration
cx repo list
cx category list
cx <category> ls
cx <category> ls --tags=demo,gpu
cx <category> find <alias-or-uid>
cx <category> info <alias> # prints path + cRef, copies to clipboard
cx <category> read <alias> # print _cmeta.yaml
cx <category> read <alias> -j --jf=meta.json10.2 Get / create / update artifacts
cx <category> add <alias> --yaml --tags=t1,t2
cx <category> add <repo>:<alias> --meta.description="..." --meta.owner=me
cx <category> update <alias> --meta.results.accuracy=0.91 --new-tags=validated
cx <category> tags <alias> --add=t1,t2 --remove=t3
cx <category> mv <old> <new>
cx <category> migrate <old> <new> # mv + a stub: the old alias keeps working (find <old> --follow_migrated=no shows the stub)
cx <category> rm <alias> # blocked if permanent: true10.3 Add a new content repo
cx repo get cmeta://<name> # cTuning zip mirror
cx repo get <alias> --url=https://github.com/<org>/<repo>
cx repo get <alias> --url=<git-url> --checkout=main
cx repo init <alias> # brand-new local repo
cx repo plug # register current dir as repo
cx repo unplug <alias> # unregister (keep files)More detail: .claude/skills/add-repo/SKILL.md.
10.4 Add a new plugin (category)
cx category add <alias>
cx <alias> --help # inherited base + your test_/test2
cx <alias> test hello --flag1
# then edit <repo>/<alias>/api/v1.pyMore detail: .claude/skills/add-plugin/SKILL.md.
10.5 Run a shipped app (the app convention)
Artifacts of category app ship a _run.bat (Windows) and _run.sh (Unix)
alongside their _cmeta.yaml. cx app run sets env vars from default_env
- any linked
configartifact, cd's into the artifact dir, and executes the script:
cx app run <app-alias> # runs _run.bat / _run.sh
cx app run <app-alias> --param.PORT=9000 # merges into env as <PREFIX>PORT
cserver # shortcut for `cx app run cserver`Relevant _cmeta.yaml fields for an app artifact: default_env: {...},
param_env_prefix: <PREFIX>_, config_name: <config-alias>, run_script: _run
(default), skip_chdir: true|false.
10.6 Debugging a call
cx <cat> <cmd> ... --debug # full dispatch trace + fail fast
cx <cat> <cmd> ... -v --con # verbose, force console
cx <cat> <cmd> ... --log_file=cx.log --log_level=DEBUG
cx <cat> <cmd> ... --repro # capture inputs/outputs
cx <cat> <cmd> ... --dump # capture full ctx10.7 Reindex when things look stale — narrowest command first
cx --reindex rebuilds every category pickle and gets slow as a home grows.
Reach for the narrow commands first; they touch one index entry or one repository:
cx <category> index <repo>:<artifact> # register ONE hand-made (mkdir-ed) artifact
cx <category> reindex <artifact> # refresh ONE record from its folder: a meta edited by hand, a folder
# renamed/moved/copied in; nothing is written on disk
cx <category> reindex # every artifact of the category, hand-made folders included
cx repo reindex <repo> # ONE repository: its _cmr.yaml and its artifacts; other repos untouched
cx <category> update <repo>:<artifact> # refresh entry after editing its _cmeta.* meta (rewrites the file too)
cx --reindex # whole-home rebuild — last resortcx <category> add <repo>:<artifact>already indexes as it creates — nothing extra needed.indexis for folders you made by hand (mkdir+_cmeta.*);reindextakes those too, and an artifact the index knows already.reindexnever touches a folder; the only record it removes is that of an artifact whose folder now holds another artifact, and it says so. A folder it cannot find, a meta it cannot read, or one UID in two folders is an error that changes nothing. After a rename by hand the new name, the UID and the old name all find the folder, and the old alias is dropped.- Editing only an artifact's payload (
api/,files/,src/,_desc.yaml) needs no reindex at all — the index tracks meta, not content. - Keep
--reindexfor the broad cases: a wipedCMETA_HOME, a bulk change across repositories, or an index that looks generally wrong. Safe, idempotent.
11. Scripting the CLI
Bash:
set -euo pipefail
out=$(cx repo list --json)
count=$(python -c "import json,sys; print(len(json.loads(sys.stdin.read())['repos']))" <<<"$out")PowerShell:
$out = cx repo list --json | ConvertFrom-Json
Write-Host "repos: $($out.repos.Count)"Windows .bat:
@echo off
set CMETA_HOME=D:\my-cmeta-home
uv run cx %*Exit codes (CI / agent integration)
The exit code of cx / cmeta is exactly the return value of the
equivalent access() call — the same numbers from the shell as from Python:
| Code | Meaning |
0 | success |
16 | soft "not found" — usually a normal branch, not a failure |
1 / 8 / 32 / 99 | real failure (generic / conflict / no such command / internal) |
Error text goes to stderr as cMeta notice: <error>!; normal output goes
to stdout.
For machine-readable results use --json_file=<path> (--jf), not
--json: --json prints the console output and a separator line before the
dict, so it is not safe to pipe into jq. Add --quiet in unattended scripts
so nothing waits on a prompt.
cx note find my-note --quiet --jf=out.json
code=$?
[ "$code" -eq 0 ] || [ "$code" -eq 16 ] || { jq -r .error out.json >&2; exit "$code"; }cx note find my-note --quiet ; $code = $LASTEXITCODE # native exe -> $LASTEXITCODE, not $?cx note find my-note --quiet
set CODE=%ERRORLEVEL%
if "%CODE%"=="16" goto :missing
:: NOTE: `if errorlevel 16` means "16 OR GREATER" - compare the variable insteadFull guide (incl. set -e interaction and debugger setup):
docs/error-handling.md.
12. Source of truth
- Global flags + descriptors:
cmeta/config.py(params_desc,params_command*_desc,params_init_desc). - Command-line parser:
cmeta/utils/cli.py::parse_cmd. - CLI entry points:
cmeta/cli.py. - Current-dir detection (
cx .):cmeta/utils/common.py::detect_cid_in_the_current_directory. - App-run convention:
cmeta/internal-repo/category/app/api/v1.py. - Companion Python skill:
.claude/skills/use-cmeta-python/SKILL.md. - User walkthrough:
docs/using-cmeta.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

