Skip to content

[FEATURE]: {env:MY_VAR} support in agent yaml #5054

Closed
ariane-emory/opencode
#30

Description

@briansunter

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

I would really like to use an env var to control which models are used in my agents.
Ideally I could do something like this but it doesn't work.

---
description: Agent description
mode: primary
model: "{env:MODEL}"
---

I'm using this as a workaround for now

  {
    "agent": {
    "myAgent": {
      "model": "{env:MODEL_NAME}"
    }
  }
}

I'm trying to do something like this to control the model across all my agents.

# HIGH tier - Complex reasoning, planning, architecture (Opus)
export OPENCODE_HIGH_MODEL=anthropic/claude-opus-4-5

# MID tier - Balanced quality/cost, planning & research (Kimi)
export OPENCODE_MID_MODEL=anthropic/claude-haiku

# LOW tier - Fast execution, validation, simple tasks (GLM-4.6)
export OPENCODE_LOW_MODEL=zai-coding-plan/glm-4.6

Activity

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Dec 4, 2025
  2. github-actions commented on Dec 4, 2025

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if these don't address your specific use case.

  3. ariane-emory commented on Dec 5, 2025

    @ariane-emory
    Contributor

    For the sake of models reading this Issue: the code that opencode uses to read this syntax in the opencode.json configuration file can be found in packages/opencode/src/config/config.ts somewhere near line ~725 or so.

    Issue #5082 is indeed very similar.

  4. strangemonad commented on Dec 5, 2025

    @strangemonad

    I'm also using the same workaround trick for both agents and commands. Would love the same env and file interpolation in all yaml front-matter.

  5. juliusz-cwiakalski commented on Jan 21, 2026

    @juliusz-cwiakalski

    I'd like to extend the original request so it also should support defaults in case env is not set, something like:

    ---
    description: Agent description
    mode: primary
    model: "{env:MODEL:-github-copilot/grok-code-fast-1}"
    ---

    consistent behaviour should apply to agents and commands. Not sure if skills can also define a model (haven't use them yet) but if yes then same behaviour there.

    Actually the {env:... should work not only work in front matter for model but also in the body of prompt - this would allow simple and powerful per-project customization of generic prompts. Example use case:

    I've an agent for managing jira tasks via mcp. It could have generic body + additional context at the end evaluated from the command. Then I could have project specific env vars set before I start Opencode (some convinience script that reads customizations for project and put's into env var would do the trick).

  6. ariane-emory commented on Jan 21, 2026

    @ariane-emory
    Contributor

    @juliusz-cwiakalski Using a different symbol such as | seems, to me, like it would be a bit clearer than making the : character polysemous and giving it two different meanings when found in different positions, why not {env:SOMEVAR|a_default_value}?

  7. juliusz-cwiakalski commented on Jan 21, 2026

    @juliusz-cwiakalski

    @ariane-emory have no strong opinion, syntax I provided is consistent with Bash syntax - but I'm fine with any other as long as it's well documented :)

  8. ariane-emory commented on Jan 21, 2026

    @ariane-emory
    Contributor

    @juliusz-cwiakalski Fair point. I don't myself use that syntax very often in bash and, being very tired when I made the comment, had momentarily forgotten about it. I retract my critique.

  9. ariane-emory commented on Jan 21, 2026

    @ariane-emory
    Contributor

    @Eric-Guo @juliusz-cwiakalski's comment about bash syntax triggered a realization I hadn't previously thought of to dawn on me: if users have written themselves custom agents meant to write (or revise) custom slash commands, performing this substitution in the body could be a breaking change for those agents.

    If the substitution were only performed in the frontmatter, a slim possibility of breakage remains: it could still break agents meant to revise slash commands that themselves used environment variable substitution in their own frontmatter or that included examples of the frontmatter of slash commands that themselves used environment variable substitution in their frontmatter - consider the scenario of an agent meant to add frontmatter using environment variable substitution to slash command), but I suspect that the possibility of breakage would be much lower.

    In those scenarios, describind in-body environment variable substitution "the old way", using shell expansion with echo $SOMEVAR could be less ambiguous. This may cause you to think about the possibility of slash commands commands that revise/create commands which themselve use shell expansions: that is indeed a similar corner case, but it's a pre-existing problem: we're already living in that world and trying to fix that existing problem would most certainly be out-of-scope-scope for this PR anyhow since it's dealing with agents, not commands.

    Much of this new critique would be also true for your other PR that permits {env:VARf) substitution in command bodies.

  10. Eric-Guo commented on Jan 22, 2026

    @Eric-Guo
    Contributor

    In those scenarios, describind in-body environment variable substitution "the old way", using shell expansion with echo $SOMEVAR

    I'm ok to let {env:MY_VAR} lives only in frontmatter, as long as I can do {exec:ECHO $MY_VAR} in markdown body when define prompt, because it's much powerful feature and cover my case. (#9261)

    But I haven't see any feature request for {exec:ECHO $MY_VAR} in agent markdown definition file so I guess we probably need to close this feature request first.

    It would be pity if @juliusz-cwiakalski @ariane-emory finally decide to let {env:MY_VAR} lives only in frontmatter only. as it's quite an inconsistent design (why MD body not work for {env:MY_VAR}?), also lead {exec:ECHO $MY_VAR} become a require for me.

    if users have written themselves custom agents meant to write (or revise) custom slash commands

    They should write custom slash command by themself, at least look at the what agent has generated for them.

  11. ariane-emory commented on Jan 22, 2026

    @ariane-emory
    Contributor

    @Eric-Guo I am in no way involved in making any decisions with regards to what actually ends up getting merged, all I can do is comment and offer my personal opinions: it is, ultimately, up to the team to decide what gets merged, not I. :)

    I do disagree pretty strongly with the claim that 'should write custom slash command by themself': I have agents write (or more often revise) custom slash commands for me all the time and it is a very powerful technique.

    Very often, the first step will be that I'll hastily write the initial version of a command, and try it out knowing full well that it probably isn't perfect.

    Inevitably, something will go awry, and then I'll call my/revise-command command that instructs the model to study what went wrong and to rewrite the command to prevent the same problem from reoccurring in the future. After doing this two or three revision cycles, I usually get a golden command that never fails.

    This technique has saved me a whole lot of work and caught corner cases in the commands that I might have never discovered on my own.

  12. Eric-Guo commented on Jan 22, 2026

    @Eric-Guo
    Contributor

    Then you need improve the document for the custom command to including your usage case.

    I also having a question, the custom command can running shell directly, so even in a rare case, you can write !echo '{env:MY_VAR}' to get what you need. But for my usage case ( {exec:ECHO $MY_VAR} in markdown body), I need propose a new FEATURE request and following PR.

    Have I mention your frontmatter only {exec:ECHO $MY_VAR} design inconsistent? I'm very willing to mention it again, it's design inconsistent.

  13. ariane-emory commented on Jan 22, 2026

    @ariane-emory
    Contributor

    @Eric-Guo The documentation for custom commands doesn't really make any effort to dive into the million different ways that custom slash commands might be used (which is perfectly fine, in my opinion). Custom slash commands are an open-ended feature that can be used in innumerable ways. IMO there's not a clear reason why my particular use case should be singled out as deserving special attention in the documentation.

    Personally, I think mine is more consistent with the existing design of only using the {env:SOMEVAR} syntax in configurations: frontmatter is parsed/validated according to the very same Zod schemas as configurations, it is in essence an embedded piece of configuration in these markdown files. There's no precedent for using that syntax outside of configurations. You are, of course, entirely free to disagree with my assessment and I do encourage you to do so: neither you nor I will make the final decision here, and it's always better if the team member that does has more well-argued opinions (and PRs) to weigh so that they may select the best option from amongst them.

    !echo '{env:MY_VAR}' is an unnecessarily complex way of achieving the intended goal: it's simpler to just !echo "$MY_VAR", which already works. For this purpose, the syntax you proposed simply adds an extra 5 characters, paying this cost in length to buy no clear gain.

  14. Eric-Guo commented on Jan 22, 2026

    @Eric-Guo
    Contributor

    !echo '{env:MY_VAR}' is an unnecessarily complex way of achieving the intended goal: it's simpler to just !echo "$MY_VAR", which already works.

    I tested in current dev, both !echo '{env:MY_VAR}' and !echo "$MY_VAR" not working in agent prompt.

    Now the problem is not inconsistent, it's not working following your suggestion. 🤷

  15. ariane-emory commented on Jan 22, 2026

    @ariane-emory
    Contributor

    @Eric-Guo Ah-hah. The syntax I gave does work in command Markdown. IMO, the simplest consistency improvement would to reuse that established syntax. Allowing shell expansions in agent Markdown files would likely open up many other possibilities I haven't myself thought of yet as well.

    I would 100% support a PR to extend the established shell expansion syntax to agent Markdown files with thumbs ups and friendly comments, but as I'm headed to bed soon anyhow I'll refrain from doing so for the moment and invite you to do so yourself if you'd care to. If you're not interested or are too busy, perhaps I might try my hand at it tomorrow.

  16. Eric-Guo commented on Jan 23, 2026

    @Eric-Guo
    Contributor

    I'm OK if #9261 can be merge, I'm not yet need shell expansion syntax in my daily needs.

  17. juliusz-cwiakalski commented on Jan 23, 2026

    @juliusz-cwiakalski

    Thanks for pushing this forward — adding my perspective as a user of agents/commands across multiple repos.

    My opinion

    I strongly prefer that interpolation works in the markdown body as well, not only in frontmatter. In practice, the body is where the productivity win is: dynamic folder names, per-repo customization blocks, injected context, etc. I also like the idea of allowing not only env vars, but (optionally) command output.

    A “safe but flexible” design idea

    To reduce ambiguity / unintended substitutions, I’d propose a two-step mechanism:

    1. Resolve dynamic values only in frontmatter (env / file / exec), producing a small set of explicitly-declared variables.
    2. Allow interpolation in the body only for those declared variables, e.g. {var:FOO} (or similar).

    This means:

    • No “free-form” {env:...} substitution inside body text unless it was explicitly declared.
    • You get body-level flexibility without surprising agents that generate prompts/commands containing {env:...} as literal examples.

    It also provides a clean mental model: frontmatter defines variables; body consumes them.

    Use cases I want to support

    1. Default model with env override
      Example: pick a sensible default model, but allow overriding it via env (or a .env file).
    2. Programmatic folder/file naming (date-based, etc.)
      Example: in a command body, generate a path containing YYYY-MM-DD using date.
    3. Generic agents with per-repo customization
      Example: a generic Jira/task agent, where each repo can inject JIRA_PROJECT_KEY, custom JQL, org-specific tags, etc., without forking the whole agent.

    Syntax: I’m flexible

    I don’t have a strong preference on syntax — I mainly care that it’s:

    • readable,
    • documented,
    • consistent across agents + commands (and ideally skills too, if they support model selection).

    That said, here are examples using one possible format. If the project prefers a different delimiter, I’m fine with that.


    Proposed example syntax (one option)

    Frontmatter resolves env, exec, file into declared variables

    • {env:NAME:-default} for env with default (bash-style).
    • {exec:...} for command output (optionally gated / opt-in).
    • Body only interpolates {var:NAME} (only declared vars).

    Example: agent markdown (frontmatter + body)

    ---
    description: Generic task manager agent (repo-customizable)
    mode: primary
    
    # Model selection: default + env override
    model: "{env:OPENCODE_HIGH_MODEL:-anthropic/claude-opus-4-5}"
    
    # Declare “safe” variables resolved only here:
    vars:
      JIRA_PROJECT: "{env:JIRA_PROJECT_KEY:-MV}"
      JIRA_BASE_URL: "{env:JIRA_BASE_URL:-https://jira.example.com}"
      DEFAULT_JQL: "{env:JIRA_DEFAULT_JQL:-project={var:JIRA_PROJECT} AND statusCategory != Done}"
    ---
    You are a task management agent for this repository.
    
    Repo customization:
    - Jira base: {var:JIRA_BASE_URL}
    - Jira project key: {var:JIRA_PROJECT}
    - Default query: {var:DEFAULT_JQL}
    
    When creating or updating tasks, use the repo’s conventions and include:
    - component/service name inferred from repository structure
    - labels: ai-agent, delivery

    Notes:

    • Only {var:...} is expanded in body.
    • {env:...} never appears in body, avoiding accidental substitutions in generated examples.

    Example: command markdown (date-based folder name)

    ---
    description: Create a dated work folder for today
    vars:
      TODAY: "{exec:date +%Y-%m-%d}"
      BASE: "{env:WORK_ROOT:-work}"
    ---
    Create folder:
    {var:BASE}/{var:TODAY}
    
    Then create a starter file:
    {var:BASE}/{var:TODAY}/notes.md

    Alternative defaults delimiter (also acceptable)

    If the project prefers a different delimiter for defaults, e.g. {env:NAME|default} instead of bash-style :-, I’m also fine with that. For example:

    • {env:OPENCODE_HIGH_MODEL|anthropic/claude-opus-4-5}
    • {env:JIRA_PROJECT_KEY|MV}

    The important part for me is:

    1. consistent across frontmatter and body consumption, and
    2. body interpolation restricted to explicitly declared variables.

    Summary

    • I want interpolation in the body too.
    • To keep it safe and predictable: resolve env/exec/file only in frontmatter, then interpolate only declared vars in body.
    • This enables defaults, date-based paths, and per-repo customizations without forking agent definitions.

    Happy to adapt the syntax examples to whatever the project decides — the behavior matters most.

  18. github-actions commented on Mar 26, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 90 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionUsed for feature requests, proposals, ideas, etc. Open discussion

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions