Summary
When the agent spec already carries an inline :name (e.g. app.py:prod), an explicit graph_name set via -g/--graph-name, [agent] graph_name, or DEEPAGENT_* is silently discarded at load time — the spec's inline name wins (correct, and documented: "overridden if spec includes :name"). But --show-config still prints the discarded value as the resolved graph_name, so the diagnostic reports a graph variable that is not the one that actually runs.
This is a --show-config advertised-vs-honored accuracy bug (same family as #108/#109/#112/#116/#128), plus a silent-flag-ignore footgun: -g looks like it took effect but didn't, and the one tool meant to reveal that (--show-config) confirms the wrong answer.
Environment
langstage-cli 0.6.30 (clean pip install langstage-cli from PyPI)
- Python 3.11, Linux
langgraph / langstage-core as pulled by the install
Minimal repro
app.py (two graphs):
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import MessagesState
from langchain_core.messages import AIMessage
def _mk(label):
def r(s): return {"messages": [AIMessage(content=f"[{label}]")]}
g = StateGraph(MessagesState); g.add_node("r", r)
g.add_edge(START, "r"); g.add_edge("r", END)
return g.compile()
prod = _mk("PROD")
staging = _mk("STAGING")
$ langstage-cli -a app.py:prod -g staging --show-config
agent_spec = app.py:prod [override] (env: LANGSTAGE_AGENT_SPEC ..., toml: agent.spec)
graph_name = staging [override] (toml: agent.graph_name)
$ langstage-cli -a app.py:prod -g staging --no-interactive "hi"
[PROD]
Same thing with an env-provided spec + a project langstage.toml (a very realistic setup — spec pinned once in the environment, graph picked per-project):
# langstage.toml -> [agent]\ngraph_name = "staging"
$ LANGSTAGE_AGENT_SPEC=app.py:prod langstage-cli --show-config
agent_spec = app.py:prod [env:LANGSTAGE_AGENT_SPEC] ...
graph_name = staging [toml (langstage.toml)] ...
$ LANGSTAGE_AGENT_SPEC=app.py:prod langstage-cli --no-interactive "hi"
[PROD]
Expected vs actual
Expected: --show-config reports the graph that will actually run. When the spec's inline :name supersedes graph_name, the diagnostic should show the effective name (prod) — ideally noting that the configured graph_name (staging) was overridden by the spec. Bonus: a one-line stderr notice when an explicit -g/graph_name is discarded because the spec pins a name, so the silent no-op is visible.
Actual: --show-config prints graph_name = staging while app.py:prod (graph PROD) runs. The explicit override is silently dropped and the diagnostic confirms the wrong value.
Root cause (pointer)
load_graph() already computes the effective name — when the spec contains :, rpartition(":") sets graph_name = tail and returns it as final_graph_name (cli.py ~L639-656, used at the run site ~L2541). --show-config renders the resolved config-level graph_name instead of this reconciled effective value, so the two disagree exactly when the spec has an inline :name and a separate graph_name is set.
Severity
Minor — no crash or data loss; requires the combination of an inline-:name spec and a separately-set graph_name. But it's a real footgun for the common "spec pinned in env, graph selected per-project/flag" pattern, and it undermines --show-config's purpose of telling the user what will actually run.
Summary
When the agent spec already carries an inline
:name(e.g.app.py:prod), an explicitgraph_nameset via-g/--graph-name,[agent] graph_name, orDEEPAGENT_*is silently discarded at load time — the spec's inline name wins (correct, and documented: "overridden if spec includes :name"). But--show-configstill prints the discarded value as the resolvedgraph_name, so the diagnostic reports a graph variable that is not the one that actually runs.This is a
--show-configadvertised-vs-honored accuracy bug (same family as #108/#109/#112/#116/#128), plus a silent-flag-ignore footgun:-glooks like it took effect but didn't, and the one tool meant to reveal that (--show-config) confirms the wrong answer.Environment
langstage-cli0.6.30 (cleanpip install langstage-clifrom PyPI)langgraph/langstage-coreas pulled by the installMinimal repro
app.py(two graphs):Same thing with an env-provided spec + a project
langstage.toml(a very realistic setup — spec pinned once in the environment, graph picked per-project):Expected vs actual
Expected:
--show-configreports the graph that will actually run. When the spec's inline:namesupersedesgraph_name, the diagnostic should show the effective name (prod) — ideally noting that the configuredgraph_name(staging) was overridden by the spec. Bonus: a one-line stderr notice when an explicit-g/graph_nameis discarded because the spec pins a name, so the silent no-op is visible.Actual:
--show-configprintsgraph_name = stagingwhileapp.py:prod(graph PROD) runs. The explicit override is silently dropped and the diagnostic confirms the wrong value.Root cause (pointer)
load_graph()already computes the effective name — when the spec contains:,rpartition(":")setsgraph_name = tailand returns it asfinal_graph_name(cli.py ~L639-656, used at the run site ~L2541).--show-configrenders the resolved config-levelgraph_nameinstead of this reconciled effective value, so the two disagree exactly when the spec has an inline:nameand a separategraph_nameis set.Severity
Minor — no crash or data loss; requires the combination of an inline-
:namespec and a separately-setgraph_name. But it's a real footgun for the common "spec pinned in env, graph selected per-project/flag" pattern, and it undermines--show-config's purpose of telling the user what will actually run.