You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Love to be able to do this to be able to read tokens automatically from spire, or run it in agent substrate and use creds injected by the substrate. With software supply chain issues growing, we shouldnt be using static tokens anymore. We're one more trivy exploit away from disaster without this sort of thing.
I sometimes use OpenCode to do basic IT work on the local computer, or even to SSH into another computer and do IT work there. Often this requires a password for sudo, or an SSH password. It would be great if there was a way I could type in my sudo or SSH password into OpenCode in such a way that it would be remembered locally, but not stored in the chat history (or sent to the model).
Thanks for the request! You're asking for an {exec:...} config substitution, next to {env:...} and {file:...}, so secrets like API keys can come from a command such as op read instead of sitting in plaintext. Maintainers will consider it.
For provider API keys you can do this now with a small local plugin. It runs your command once at startup and sets the provider's apiKey. Save it as .opencode/plugins/exec-secrets.ts in your project, or in ~/.config/opencode/plugins/ to use it everywhere:
import{Plugin}from"@opencode/plugin"import{execSync}from"node:child_process"// providerID -> shell command that prints the API key on stdoutconstcommands: Record<string,string>={anthropic: "op read 'op://Vault/Provider/token'",}exportdefaultPlugin.define({id: "local.exec-secrets",asyncsetup(ctx){constkeys=Object.fromEntries(Object.entries(commands).map(([id,command])=>[id,execSync(command,{encoding: "utf8",stdio: ["ignore","pipe","inherit"]}).trim(),]),)awaitctx.provider.transform((editor)=>{for(const[id,apiKey]ofObject.entries(keys)){if(!editor.get(id))continueeditor.update(id,(provider)=>{provider.settings={ ...provider.settings, apiKey }})}})},})
I've checked that this type-checks against the v2 plugin API, but I haven't run it in a live session. With it in place you can leave apiKey out of your opencode.json. It only covers provider API keys; a general {exec:} that works in any config field would need support in OpenCode itself.
Thanks for the request! You're asking for an {exec:...} config substitution, next to {env:...} and {file:...}, so secrets like API keys can come from a command such as op read instead of sitting in plaintext. Maintainers will consider it.
For provider API keys you can do this now with a small local plugin. It runs your command once at startup and sets the provider's apiKey. Save it as .opencode/plugins/exec-secrets.ts in your project, or in ~/.config/opencode/plugins/ to use it everywhere:
import { Plugin } from "@opencode/plugin"
import { execSync } from "node:child_process"
// providerID -> shell command that prints the API key on stdout
const commands: Record<string, string> = {
anthropic: "op read 'op://Vault/Provider/token'",
}
export default Plugin.define({
id: "local.exec-secrets",
async setup(ctx) {
const keys = Object.fromEntries(
Object.entries(commands).map(([id, command]) => [
id,
execSync(command, { encoding: "utf8", stdio: ["ignore", "pipe", "inherit"] }).trim(),
]),
)
await ctx.provider.transform((editor) => {
for (const [id, apiKey] of Object.entries(keys)) {
if (!editor.get(id)) continue
editor.update(id, (provider) => {
provider.settings = { ...provider.settings, apiKey }
})
}
})
},
})
I've checked that this type-checks against the v2 plugin API, but I haven't run it in a live session. With it in place you can leave apiKey out of your opencode.json. It only covers provider API keys; a general {exec:} that works in any config field would need support in OpenCode itself.
Is this AI Slop? There already was a PR and implementation of this and the maintainers did nothing with it until the AI autoclosed it.
import{Plugin}from"@opencode/plugin";import{execSync}from"node:child_process";// Infomaniak is a models.dev catalog provider: opencode derives its baseURL from// $INFOMANIAK_PRODUCT_ID and resolves the credential from $INFOMANIAK_API_KEY at// request time. Only the key is secret; fetch it from gopass into the environment.exportdefaultPlugin.define({id: "local.exec-secrets",asyncsetup(){process.env.INFOMANIAK_API_KEY=execSync("gopass show infomaniak_api_key",{encoding: "utf8",stdio: ["ignore","pipe","inherit"],}).trim();},});
Activity
github-actions commentedon Jan 9, 2026
This issue might be a duplicate of existing issues. Please check:
Feel free to ignore if none of these address your specific case.
nikaro commentedon Jan 17, 2026
@thdxr any chance this would get accepted as a feature? 🥺
nikaro commentedon Jan 20, 2026
Closing in favor of older issue: #231
nikaro commentedon Sep 24, 2026
Re-opening as #231 has been closed without solution.
At the time i did an implementation PR: #8917
kfox1111 commentedon Oct 1, 2026
Love to be able to do this to be able to read tokens automatically from spire, or run it in agent substrate and use creds injected by the substrate. With software supply chain issues growing, we shouldnt be using static tokens anymore. We're one more trivy exploit away from disaster without this sort of thing.
tkoop commentedon Oct 1, 2026
I sometimes use OpenCode to do basic IT work on the local computer, or even to SSH into another computer and do IT work there. Often this requires a password for sudo, or an SSH password. It would be great if there was a way I could type in my sudo or SSH password into OpenCode in such a way that it would be remembered locally, but not stored in the chat history (or sent to the model).
(Cursor does this very nicely.)
opencodejr commentedon Oct 29, 2026
Thanks for the request! You're asking for an
{exec:...}config substitution, next to{env:...}and{file:...}, so secrets like API keys can come from a command such asop readinstead of sitting in plaintext. Maintainers will consider it.Related:
For provider API keys you can do this now with a small local plugin. It runs your command once at startup and sets the provider's
apiKey. Save it as.opencode/plugins/exec-secrets.tsin your project, or in~/.config/opencode/plugins/to use it everywhere:I've checked that this type-checks against the v2 plugin API, but I haven't run it in a live session. With it in place you can leave
apiKeyout of youropencode.json. It only covers provider API keys; a general{exec:}that works in any config field would need support in OpenCode itself.tthoma24 commentedon Oct 29, 2026
Is this AI Slop? There already was a PR and implementation of this and the maintainers did nothing with it until the AI autoclosed it.
nikaro commentedon Nov 6, 2026
It actually works. Good enough for me. Feel free to close the issue if you consider it does not have its place in OpenCode core.Edit: Actually maybe not, it though it worked because the
opencode server --servicefrom another session was still running...nikaro commentedon Nov 7, 2026
Here is what worked: