feat(cli): alias subcommand; remove --alias flag (RFC-011 D4) (#244)

Operator aliases move from the --alias flag on query/mutate to a dedicated 'omnigraph alias <name> [args]' subcommand, so an alias can never shadow or be shadowed by a built-in verb. Unknown name errors listing defined aliases. Removes the legacy alias machinery from query/mutate (net -156 lines); legacy omnigraph.yaml aliases lose their CLI entry point.
This commit is contained in:
Andrew Altshuler 2026-06-15 15:23:03 +03:00 committed by GitHub
parent 2ed05d2cb1
commit b395757e21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 128 additions and 379 deletions

View file

@ -99,12 +99,10 @@ pub(crate) enum Command {
legacy_uri: Option<String>,
#[arg(long)]
config: Option<PathBuf>,
#[arg(long, conflicts_with_all = ["query", "query_string"])]
alias: Option<String>,
#[arg(long, conflicts_with_all = ["alias", "query_string"])]
#[arg(long, conflicts_with = "query_string")]
query: Option<PathBuf>,
/// Inline GQ source — alternative to `--query <path>` and `--alias <name>`.
#[arg(short = 'e', long = "query-string", value_name = "GQ", conflicts_with_all = ["query", "alias"])]
/// Inline GQ source — alternative to `--query <path>`.
#[arg(short = 'e', long = "query-string", value_name = "GQ", conflicts_with = "query")]
query_string: Option<String>,
#[arg(long)]
name: Option<String>,
@ -118,8 +116,6 @@ pub(crate) enum Command {
format: Option<ReadOutputFormat>,
#[arg(long, conflicts_with = "format")]
json: bool,
#[arg()]
alias_args: Vec<String>,
},
/// Execute a graph mutation query against a branch.
///
@ -135,12 +131,10 @@ pub(crate) enum Command {
legacy_uri: Option<String>,
#[arg(long)]
config: Option<PathBuf>,
#[arg(long, conflicts_with_all = ["query", "query_string"])]
alias: Option<String>,
#[arg(long, conflicts_with_all = ["alias", "query_string"])]
#[arg(long, conflicts_with = "query_string")]
query: Option<PathBuf>,
/// Inline GQ source — alternative to `--query <path>` and `--alias <name>`.
#[arg(short = 'e', long = "query-string", value_name = "GQ", conflicts_with_all = ["query", "alias"])]
/// Inline GQ source — alternative to `--query <path>`.
#[arg(short = 'e', long = "query-string", value_name = "GQ", conflicts_with = "query")]
query_string: Option<String>,
#[arg(long)]
name: Option<String>,
@ -150,8 +144,28 @@ pub(crate) enum Command {
branch: Option<String>,
#[arg(long)]
json: bool,
#[arg()]
alias_args: Vec<String>,
},
/// Invoke an operator alias (RFC-011 Decision 4).
///
/// An alias is a personal binding under `aliases:` in
/// ~/.omnigraph/config.yaml — name → (server, graph, stored-query name,
/// default params). `omnigraph alias <name> [args]` invokes the bound
/// stored query on its server. Living in its own namespace, an alias can
/// never shadow or be shadowed by a built-in verb. Replaces the removed
/// `--alias` flag on `query`/`mutate`.
Alias {
/// Alias name (a key under `aliases:` in ~/.omnigraph/config.yaml).
name: String,
/// Positional args bound to the alias's declared `args` params, in order.
args: Vec<String>,
#[arg(long)]
config: Option<PathBuf>,
#[command(flatten)]
params: ParamsArgs,
#[arg(long, conflicts_with = "json")]
format: Option<ReadOutputFormat>,
#[arg(long, conflicts_with = "format")]
json: bool,
},
/// Load data into a graph (local or remote)
Load {

View file

@ -729,44 +729,6 @@ pub(crate) fn parse_alias_value(value: &str) -> Value {
serde_json::from_str(value).unwrap_or_else(|_| Value::String(value.to_string()))
}
pub(crate) fn merged_params_json(
alias_name: Option<&str>,
alias_arg_names: &[String],
alias_arg_values: &[String],
explicit: Option<Value>,
) -> Result<Option<Value>> {
if alias_arg_values.len() > alias_arg_names.len() {
let alias = alias_name.unwrap_or("<alias>");
bail!(
"alias '{}' expects at most {} args but got {}",
alias,
alias_arg_names.len(),
alias_arg_values.len()
);
}
let mut merged = serde_json::Map::new();
for (arg_name, arg_value) in alias_arg_names.iter().zip(alias_arg_values.iter()) {
merged.insert(arg_name.clone(), parse_alias_value(arg_value));
}
match explicit {
Some(Value::Object(object)) => {
for (key, value) in object {
merged.insert(key, value);
}
}
Some(_) => bail!("params JSON must be an object"),
None => {}
}
if merged.is_empty() {
Ok(None)
} else {
Ok(Some(Value::Object(merged)))
}
}
/// The format cascade (RFC-007 §D3): `--json` > `--format` > alias format >
/// legacy `cli.output_format` (RFC-008 window) > operator `defaults.output`
/// > table.
@ -790,43 +752,6 @@ pub(crate) fn resolve_read_format(
.unwrap_or_default()
}
pub(crate) fn resolve_alias<'a>(
config: &'a OmnigraphConfig,
alias_name: Option<&'a str>,
expected: AliasCommand,
) -> Result<Option<(&'a str, &'a omnigraph_server::AliasConfig)>> {
let Some(alias_name) = alias_name else {
return Ok(None);
};
let alias = config.alias(alias_name)?;
if alias.command != expected {
bail!(
"alias '{}' is a {:?} alias, not a {:?} alias",
alias_name,
alias.command,
expected
);
}
Ok(Some((alias_name, alias)))
}
pub(crate) fn normalize_legacy_alias_uri(
uri: Option<String>,
target_available: bool,
alias_name: Option<&str>,
mut alias_args: Vec<String>,
) -> (Option<String>, Vec<String>) {
let Some(candidate) = uri else {
return (None, alias_args);
};
if alias_name.is_some() && target_available {
alias_args.insert(0, candidate);
return (None, alias_args);
}
(Some(candidate), alias_args)
}
pub(crate) fn read_target_from_cli(branch: Option<String>, snapshot: Option<String>) -> ReadTarget {

View file

@ -28,7 +28,7 @@ use omnigraph_api_types::{
};
use omnigraph_server::queries::{QueryRegistry, check, format_check_breakages};
use omnigraph_server::{
AliasCommand, OmnigraphConfig, PolicyAction, PolicyDecision, PolicyEngine, PolicyRequest,
OmnigraphConfig, PolicyAction, PolicyDecision, PolicyEngine, PolicyRequest,
PolicyTestConfig, ReadOutputFormat, graph_resource_id_for_selection, load_config,
};
use reqwest::Method;
@ -569,7 +569,6 @@ async fn main() -> Result<()> {
uri,
legacy_uri,
config,
alias,
query,
query_string,
name,
@ -578,182 +577,61 @@ async fn main() -> Result<()> {
snapshot,
format,
json,
alias_args,
} => {
if alias.is_none() && query.is_none() && query_string.is_none() {
bail!("exactly one of --query, --query-string, or --alias must be provided");
if query.is_none() && query_string.is_none() {
bail!("provide a query: --query <file> or -e '<inline gq>'");
}
let config = load_cli_config(config.as_ref())?;
// Operator aliases (RFC-007 PR 3): pure bindings to stored
// queries. A legacy file-alias with the same name wins during
// the RFC-008 window (with a warning); an alias name found
// only in the operator layer takes the invoke path here.
if let Some(alias_name) = alias.as_deref() {
let operator_config = crate::operator::load_operator_config()?;
if let Some(operator_alias) = operator_config.aliases.get(alias_name) {
if config.alias(alias_name).is_ok() {
eprintln!(
"warning: alias '{alias_name}' is defined in both omnigraph.yaml (legacy, wins during the deprecation window) and the operator config; the legacy definition applies"
);
} else {
// The hidden legacy-uri positional swallows the first
// bare arg; an operator alias always knows its target,
// so reclaim it as the first positional param.
let (_, alias_args) = normalize_legacy_alias_uri(
legacy_uri.clone(),
true,
Some(alias_name),
alias_args.clone(),
);
let output = execute_operator_alias(
&http_client,
&config,
alias_name,
operator_alias,
&alias_args,
load_params_json(&params)?,
)
.await?;
let format =
resolve_read_format(&config, format, json, operator_alias.format);
print_read_output(&output, format, &config)?;
return Ok(());
}
}
}
let alias = resolve_alias(&config, alias.as_deref(), AliasCommand::Read)?;
let alias_name = alias.as_ref().map(|(name, _)| *name);
let alias_config = alias.as_ref().map(|(_, alias)| *alias);
let alias_graph = alias_config.and_then(|alias| alias.graph.as_deref());
let target_available = alias_graph.is_some() || config.cli_graph_name().is_some();
let (legacy_uri, alias_args) =
normalize_legacy_alias_uri(legacy_uri, target_available, alias_name, alias_args);
// `--target` is gone; resolve an alias's legacy `graph` name to its
// URI (a positional URI still wins).
let uri = match uri.or(legacy_uri) {
Some(uri) => Some(uri),
None => match alias_graph {
Some(name) => Some(config.resolve_target_uri(None, Some(name), None)?),
None => None,
},
};
let client = client::GraphClient::resolve(
&config,
cli.server.as_deref(),
cli.graph.as_deref(),
uri,
uri.or(legacy_uri),
cli.profile.as_deref(),
cli.store.as_deref(),
)?;
let query_source = resolve_query_source(
&config,
query.as_ref(),
query_string.as_deref(),
alias_config.map(|a| a.query.as_str()),
)?;
let params_json = merged_params_json(
alias_name,
alias_config
.map(|alias| alias.args.as_slice())
.unwrap_or(&[]),
&alias_args,
load_params_json(&params)?,
)?;
let target = resolve_read_target(
&config,
branch,
snapshot,
alias_config.and_then(|alias| alias.branch.clone()),
)?;
let query_name = name.or_else(|| alias_config.and_then(|alias| alias.name.clone()));
let query_source =
resolve_query_source(&config, query.as_ref(), query_string.as_deref(), None)?;
let params_json = load_params_json(&params)?;
let target = resolve_read_target(&config, branch, snapshot, None)?;
let output = client
.query(
target,
&query_source,
query_name.as_deref(),
params_json.as_ref(),
)
.query(target, &query_source, name.as_deref(), params_json.as_ref())
.await?;
let format = resolve_read_format(
&config,
format,
json,
alias_config.and_then(|alias| alias.format),
);
let format = resolve_read_format(&config, format, json, None);
print_read_output(&output, format, &config)?;
}
Command::Mutate {
uri,
legacy_uri,
config,
alias,
query,
query_string,
name,
params,
branch,
json,
alias_args,
} => {
if alias.is_none() && query.is_none() && query_string.is_none() {
bail!("exactly one of --query, --query-string, or --alias must be provided");
if query.is_none() && query_string.is_none() {
bail!("provide a mutation query: --query <file> or -e '<inline gq>'");
}
let config = load_cli_config(config.as_ref())?;
let alias = resolve_alias(&config, alias.as_deref(), AliasCommand::Change)?;
let alias_name = alias.as_ref().map(|(name, _)| *name);
let alias_config = alias.as_ref().map(|(_, alias)| *alias);
let alias_graph = alias_config.and_then(|alias| alias.graph.as_deref());
let target_available = alias_graph.is_some() || config.cli_graph_name().is_some();
let (legacy_uri, alias_args) =
normalize_legacy_alias_uri(legacy_uri, target_available, alias_name, alias_args);
// `--target` is gone; resolve an alias's legacy `graph` name to its
// URI (a positional URI still wins).
let uri = match uri.or(legacy_uri) {
Some(uri) => Some(uri),
None => match alias_graph {
Some(name) => Some(config.resolve_target_uri(None, Some(name), None)?),
None => None,
},
};
let client = client::GraphClient::resolve_with_policy(
&config,
cli.server.as_deref(),
cli.graph.as_deref(),
uri,
uri.or(legacy_uri),
cli.as_actor.as_deref(),
cli.profile.as_deref(),
cli.store.as_deref(),
)?;
let query_source = resolve_query_source(
&config,
query.as_ref(),
query_string.as_deref(),
alias_config.map(|a| a.query.as_str()),
)?;
let params_json = merged_params_json(
alias_name,
alias_config
.map(|alias| alias.args.as_slice())
.unwrap_or(&[]),
&alias_args,
load_params_json(&params)?,
)?;
let branch = resolve_branch(
&config,
branch,
alias_config.and_then(|alias| alias.branch.clone()),
"main",
);
let query_name = name.or_else(|| alias_config.and_then(|alias| alias.name.clone()));
let query_source =
resolve_query_source(&config, query.as_ref(), query_string.as_deref(), None)?;
let params_json = load_params_json(&params)?;
let branch = resolve_branch(&config, branch, None, "main");
let output = client
.mutate(
&branch,
&query_source,
query_name.as_deref(),
params_json.as_ref(),
)
.mutate(&branch, &query_source, name.as_deref(), params_json.as_ref())
.await?;
if json {
print_json(&output)?;
@ -761,6 +639,37 @@ async fn main() -> Result<()> {
print_change_human(&output);
}
}
Command::Alias {
name,
args,
config,
params,
format,
json,
} => {
let config = load_cli_config(config.as_ref())?;
let operator_config = crate::operator::load_operator_config()?;
let Some(operator_alias) = operator_config.aliases.get(&name) else {
let defined: Vec<&str> =
operator_config.aliases.keys().map(String::as_str).collect();
bail!(
"unknown alias '{name}'; defined aliases: [{}] \
(add it under `aliases:` in ~/.omnigraph/config.yaml)",
defined.join(", ")
);
};
let output = execute_operator_alias(
&http_client,
&config,
&name,
operator_alias,
&args,
load_params_json(&params)?,
)
.await?;
let format = resolve_read_format(&config, format, json, operator_alias.format);
print_read_output(&output, format, &config)?;
}
Command::Policy { command } => match command {
PolicyCommand::Validate { config } => {
let config = load_cli_config(config.as_ref())?;

View file

@ -106,6 +106,7 @@ pub(crate) fn command_plane(cmd: &Command) -> Plane {
match cmd {
Command::Query { .. }
| Command::Mutate { .. }
| Command::Alias { .. }
| Command::Load { .. }
| Command::Ingest { .. }
| Command::Branch { .. }
@ -168,6 +169,7 @@ pub(crate) fn command_label(cmd: &Command) -> &'static str {
Command::Commit { .. } => "commit",
Command::Query { .. } => "query",
Command::Mutate { .. } => "mutate",
Command::Alias { .. } => "alias",
Command::Policy { .. } => "policy",
Command::Optimize { .. } => "optimize",
Command::Repair { .. } => "repair",

View file

@ -505,10 +505,9 @@ query list_people() {
#[test]
fn deprecated_read_and_change_subcommands_emit_warnings() {
// Both subcommands require `--query`/`--query-string`/`--alias`, so
// invoking them with no args will exit non-zero. That's fine --
// we only care that the deprecation warning is printed before the
// argument-required error.
// Both subcommands require `--query`/`--query-string`, so invoking them
// with no args will exit non-zero. That's fine -- we only care that the
// deprecation warning is printed before the argument-required error.
let output = cli().arg("read").output().unwrap();
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(

View file

@ -2,7 +2,6 @@
//! Moved verbatim from tests/cli.rs in the modularization.
use serde_json::Value;
use tempfile::tempdir;
mod support;
@ -57,141 +56,42 @@ query list_people() {
assert_eq!(stdout_string(&lint_output), stdout_string(&check_output));
}
// Legacy `omnigraph.yaml` `aliases:` invoked via the `--alias` flag were
// removed in RFC-011 D4 — operator aliases now live under `omnigraph alias
// <name>` (the happy path is covered by system_local's operator-alias e2e).
// The legacy file-alias path has no CLI entry point.
#[test]
fn read_alias_from_yaml_config_runs_with_kv_output() {
let temp = tempdir().unwrap();
let graph = graph_path(temp.path());
let config = temp.path().join("omnigraph.yaml");
let query = temp.path().join("aliases.gq");
init_graph(&graph);
load_fixture(&graph);
write_query_file(
&query,
&std::fs::read_to_string(fixture("test.gq")).unwrap(),
fn alias_flag_is_removed_from_query() {
// RFC-011 D4: `--alias` no longer exists on query/mutate; use `alias <name>`.
let output = output_failure(cli().arg("query").arg("--alias").arg("who"));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("unexpected argument") && stderr.contains("--alias"),
"expected clap to reject --alias on query; got: {stderr}"
);
write_config(
&config,
&format!(
"{}aliases:\n owner:\n command: read\n query: aliases.gq\n name: get_person\n args: [name]\n format: kv\n",
local_yaml_config(&graph)
),
);
let output = output_success(
cli()
.arg("read")
.arg("--config")
.arg(&config)
.arg("--alias")
.arg("owner")
.arg("Alice"),
);
let stdout = stdout_string(&output);
assert!(stdout.contains("row 1"));
assert!(stdout.contains("p.name: Alice"));
}
#[test]
fn read_alias_uses_alias_target_without_cli_default_and_accepts_url_like_arg() {
let temp = tempdir().unwrap();
let graph = graph_path(temp.path());
let config = temp.path().join("omnigraph.yaml");
let query = temp.path().join("aliases.gq");
let data = temp.path().join("url-like.jsonl");
init_graph(&graph);
write_jsonl(
&data,
r#"{"type":"Person","data":{"name":"https://example.com","age":30}}"#,
);
output_success(
fn alias_unknown_name_errors_listing_defined() {
// Hermetic: an unknown alias fails before any network, listing defined ones.
let home = tempdir().unwrap();
std::fs::write(
home.path().join("config.yaml"),
"servers:\n dev:\n url: https://x\naliases:\n who:\n server: dev\n query: find_person\n",
)
.unwrap();
let output = output_failure(
cli()
.arg("load")
.arg("--mode")
.arg("overwrite")
.arg("--data")
.arg(&data)
.arg(&graph),
.env("OMNIGRAPH_HOME", home.path())
.arg("alias")
.arg("nope"),
);
write_query_file(
&query,
&std::fs::read_to_string(fixture("test.gq")).unwrap(),
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("unknown alias 'nope'") && stderr.contains("who"),
"expected an unknown-alias error listing defined aliases; got: {stderr}"
);
write_config(
&config,
&format!(
"graphs:\n local:\n uri: '{}'\nquery:\n roots:\n - .\npolicy: {{}}\naliases:\n owner:\n command: read\n query: aliases.gq\n name: get_person\n args: [name]\n graph: local\n format: kv\n",
graph.to_string_lossy()
),
);
let output = output_success(
cli()
.arg("read")
.arg("--config")
.arg(&config)
.arg("--alias")
.arg("owner")
.arg("https://example.com"),
);
let stdout = stdout_string(&output);
assert!(stdout.contains("row 1"));
assert!(stdout.contains("p.name: https://example.com"));
}
#[test]
fn change_alias_from_yaml_config_persists_changes() {
let temp = tempdir().unwrap();
let graph = graph_path(temp.path());
let config = temp.path().join("omnigraph.yaml");
let query = temp.path().join("mutations.gq");
init_graph(&graph);
load_fixture(&graph);
write_query_file(
&query,
r#"
query insert_person($name: String, $age: I32) {
insert Person { name: $name, age: $age }
}
"#,
);
write_config(
&config,
&format!(
"{}aliases:\n add_person:\n command: change\n query: mutations.gq\n name: insert_person\n args: [name, age]\n",
local_yaml_config(&graph)
),
);
let output = output_success(
cli()
.arg("change")
.arg("--config")
.arg(&config)
.arg("--alias")
.arg("add_person")
.arg("Eve")
.arg("29")
.arg("--json"),
);
let payload: Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(payload["affected_nodes"], 1);
let verify = output_success(
cli()
.arg("read")
.arg(&graph)
.arg("--query")
.arg(fixture("test.gq"))
.arg("--name")
.arg("get_person")
.arg("--params")
.arg(r#"{"name":"Eve"}"#)
.arg("--json"),
);
let verify_payload: Value = serde_json::from_slice(&verify.stdout).unwrap();
assert_eq!(verify_payload["row_count"], 1);
}
#[test]

View file

@ -2480,12 +2480,11 @@ fn local_cli_operator_alias_and_server_flag_invoke_stored_query() {
.unwrap();
}
// The operator alias: name + positional arg, nothing else — server,
// The operator alias (RFC-011 D4): `alias <name> [args]` — server,
// graph, stored query, and token all resolve from the operator layer.
let output = cli()
.env("OMNIGRAPH_HOME", operator_home.path())
.arg("query")
.arg("--alias")
.arg("alias")
.arg("who")
.arg("Alice")
.arg("--json")

View file

@ -30,8 +30,9 @@ omnigraph mutate --uri graph.omni \
--params '{"name":"Inline","age":42}'
```
`-e` is mutually exclusive with `--query <path>` and `--alias <name>`; exactly
one of the three must be provided. The inline source travels through the same
`-e` is mutually exclusive with `--query <path>`; exactly one of the two must be
provided. (Operator aliases moved to their own `omnigraph alias <name>`
subcommand — RFC-011 D4.) The inline source travels through the same
parser, lint, params binding, and commit machinery as a file-based query —
only the source loader changes.

View file

@ -11,8 +11,9 @@ Top-level command families and subcommands. Graph-targeting commands accept a po
| `init` | `--schema <pg>` → initialize a graph (no longer scaffolds `omnigraph.yaml`; start cluster configs from the [cluster.md](../clusters/index.md) quick-start or `config migrate`) |
| `load` | bulk load a branch, local or remote (`--mode overwrite\|append\|merge` is **required** — overwrite is destructive, so there is no default). Without `--from` the target branch must exist; `--from <base>` forks a missing `--branch` from `<base>` first |
| `ingest` | deprecated alias of `load --from <base>` (defaults: `--from main --mode merge`); prints a one-line warning to stderr |
| `query` (alias: `read`) | run named read query; source via `--query <path>`, `-e`/`--query-string <GQ>`, or `--alias <name>` (exactly one). `read` is the deprecated previous name and prints a one-line warning to stderr |
| `mutate` (alias: `change`) | run mutation query; same `--query` / `-e` / `--alias` mutual-exclusion as `query`. `change` is the deprecated previous name and prints a one-line warning to stderr |
| `query` (alias: `read`) | run a read query; source via `--query <path>` or `-e`/`--query-string <GQ>`. `read` is the deprecated previous name and prints a one-line warning to stderr |
| `mutate` (alias: `change`) | run a mutation query; same `--query` / `-e` source as `query`. `change` is the deprecated previous name and prints a one-line warning to stderr |
| `alias <name> [args]` | invoke an operator alias — a personal binding (under `aliases:` in `~/.omnigraph/config.yaml`) to a stored query on a named server (RFC-011 D4; replaces the removed `--alias` flag) |
| `snapshot` | print current snapshot (per-table version + row count) |
| `export` | dump to JSONL on stdout (`--type T`, `--table K` filters) |
| `branch create \| list \| delete \| merge` | branching ops |
@ -146,10 +147,12 @@ aliases:
format: table
```
`omnigraph query --alias triage 2026-06-01` invokes
`omnigraph alias triage 2026-06-01` invokes
`POST <server>/graphs/spike/queries/weekly_triage` with the keyed
credential. A legacy `omnigraph.yaml` alias with the same name wins during
the deprecation window (with a warning).
credential. Aliases live in their own `alias` namespace (RFC-011 Decision 4),
so an alias can never shadow — or be shadowed by — a built-in verb. (The old
`--alias <name>` flag on `query`/`mutate` was removed; legacy `omnigraph.yaml`
`aliases:` no longer have a CLI entry point.)
A remote command whose URL prefix-matches an operator server's `url` (the
`gh` host model — no flags needed) resolves its token through:
@ -199,14 +202,11 @@ query:
roots: [<dir>, …] # search path for .gq files
auth:
env_file: .env.omni
aliases:
<alias>:
# accepted values: `read` / `query` (read alias), `change` / `mutate`
# (write alias). `query` and `mutate` are recommended; `read` and
# `change` remain accepted forever for back-compat.
command: read|change|query|mutate
query: <path-to-.gq>
name: <query-name>
aliases: # legacy file-aliases — parsed but no longer
<alias>: # reachable from the CLI (RFC-011 D4 removed
command: read|change|query|mutate # the `--alias` flag). Use operator
query: <path-to-.gq> # aliases (`~/.omnigraph/config.yaml`
name: <query-name> # `aliases:`) via `omnigraph alias <name>`.
args: [<positional-name>, …]
graph: <name>
branch: <name>