How We Secured a Vercel eve Agent by Giving It Zero CredentialsJoin us July 22:Secrets Management in the AI Era webinar. Save your seat.
27kRequest a demoGet started for free
27k starsRequest a demoGet started for free
← Back<br>Blog post • 11 min read<br>How We Secured a Vercel eve Agent by Giving It Zero Credentials
Published onThursday, July 9, 2026
Vercel just shipped eve, an open source framework for building AI agents. It promises to do for agents what Next.js did for web apps, collapse the architecture into a folder and file structure instead of a pile of glue code.
With eve, the entire agent is a file directory: the instructions it follows, the tools it can call, the specialists it can delegate to, the places people can reach it.
We built one to see how far that pitch holds up, and to test something else at the same time. We prototyped a support agent for the Infisical open source community: it needed to read our codebase and answer questions about the CLI or platform, with citations to the actual source. That agent needed real credentials to do the job, a model API key and a GitHub token, and we didn't want either one anywhere near its own process. So we routed everything through Agent Vault, an open source credential proxy and vault, and watched the agent do real work while holding none of the keys that made it possible.
The folder is the architecture
Open an eve project and the directory tells you almost everything about what the agent does:
agent/<br>agent.ts model + config<br>instructions.md who the agent is<br>tools/ custom capabilities<br>skills/ playbooks the agent loads on demand<br>connections/ external tools and MCP servers<br>subagents/ specialists it can delegate to<br>channels/ where people reach it (Slack, web, HTTP)<br>schedules/ cron-triggered runs
That's the whole mental model. A file's name and its place in the tree define what it does. Compare that to hand-rolling an agent on a raw model API, where the "architecture" lives across a dozen scattered files and a system prompt nobody wants to touch, and the appeal is obvious.
A few pieces are worth walking through, because they're what let us build our credential setup without writing much extra code.
Model choice is one line. agent.ts exports the config, and the model is a single field: model: "anthropic/claude-sonnet-5". eve routes that string through Vercel's AI Gateway by default, but it can also call any other LLM API directly, and it accepts fallbacks. Our main agent runs on Claude Sonnet for routine questions. The code-researcher subagent, the specialist that digs through code on harder questions, points at Opus in its own agent.ts, just by naming a different string.
Tools are typed functions with the built-ins already done for you. Web search, fetching a URL, reading and writing files, running shell commands, these ship out of the box. When we needed something specific, a function that hands back our canonical docs and GitHub links so the agent points people to the real page instead of guessing a URL, we wrote it as a typed function in tools/: defineTool wrapping a Zod schema for the input and an execute function that does the lookup. The model only ever sees what execute returns, never the code or the credentials behind it.
Connections saved us the most time, and they're the part our credential story runs through. Wiring up GitHub by hand on a typical agent SDK means writing each tool call yourself: list issues, get a file, search code, one function per endpoint. In eve, a connection is one file pointing at a server, and the agent discovers the whole toolset on demand. Ours is connections/github.ts, defineMcpClientConnection pointed at GitHub's own hosted MCP (Model Context Protocol) server with a getToken callback reading process.env.GITHUB_TOKEN. The moment that file existed, the agent could search issues, read files, and open pull requests, without us writing a single GitHub-specific function. That GITHUB_TOKEN is exactly the value we're about to hollow out.
Subagents let the main agent stay lean. Ours delegates code questions to a code-researcher subagent with its own prompt, its own sandbox, and its own model, defined the same way as the main agent's but living at subagents/code-researcher/agent.ts. It clones our repos, greps the real source, and comes back with a file and a line number instead of a guess, which is the whole point of building a support agent that answers from our actual codebase instead of from a model's memory of it.
Channels are different front doors to the same agent. There's a plain HTTP endpoint you can hit with curl, a web chat component you can drop into a Next.js site, and platform channels for Slack and Discord that answer mentions and DMs where a team already works. We didn't have to write anything for the HTTP endpoint since eve enables it by default. But we can separately configure slack.ts, discord.ts, or anything else. This avoids creating parallel agents and means an update is reflected across...