Skip to content
Agentmart
Submit a tool

AGENTS.md · vellum-ai/vellum-assistant

AGENTS.md from vellum-ai/vellum-assistant: 371 lines covering Project Structure, Intellectual Honesty, Development, Dependencies and more.

Template by vellum-ai

IndexedMIT★ 1,449
Write a review

Install

Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/vellum-ai/vellum-assistant/main/AGENTS.md -o AGENTS.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The AGENTS.md file that vellum-ai/vellum-assistant (1,449 stars) keeps for coding agents. It has 371 lines in 20 sections: Project Structure; Intellectual Honesty; Development; Dependencies; Cutting Releases; Testing; PR Workflow; Keep Docs Up to Date; Worktrees & Source Control; Single Source of Truth; Dead Code Removal; Code Comments; Em Dashes; Unknown Data Validation; Control-Flow Braces; Generic Examples; Backwards Compatibility; Multi-Client Assistant State Sync; Assistant-Driven Judgement; Cross-Package Import Boundary. Use it as a model for your own project's instructions.

Use cases: code-generation, testing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.

For
Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
Length
371 lines
File
AGENTS.md

Sections

  1. Project Structure
  2. Intellectual Honesty
  3. Development
  4. Dependencies
  5. Cutting Releases
  6. Testing
  7. PR Workflow
  8. Keep Docs Up to Date
  9. Worktrees & Source Control
  10. Single Source of Truth
  11. Dead Code Removal
  12. Code Comments
  13. Em Dashes
  14. Unknown Data Validation
  15. Control-Flow Braces
  16. Generic Examples
  17. Backwards Compatibility
  18. Multi-Client Assistant State Sync
  19. Assistant-Driven Judgement
  20. Cross-Package Import Boundary

First lines (shown under the repo's MIT license)

# Vellum Assistant — Agent Instructions

## Project Structure

Bun + TypeScript monorepo with multiple packages:

- `clients/`: End-user app surfaces: `clients/web/` (Vite + React Router v7 SPA), `clients/ios/` (Capacitor iOS shell that loads the web app in a WKWebView), `clients/android/` (Capacitor Android shell that loads the web app in a WebView), `clients/macos/` (Electron desktop shell that wraps `clients/web/`; daemon/gateway lifecycle is owned by the `vellum` CLI, which the app invokes as a subprocess; auto-update via `electron-updater`; CI workflows are `pr-macos.yaml` / `ci-main-macos.yaml`), `clients/linux/` (Electron desktop shell around `clients/web/` packaged as an AppImage; CI workflows are `pr-linux.yaml` / `ci-main-linux.yaml`), `clients/windows/` (Electron desktop shell around `clients/web/` at capability parity with macOS, see `clients/windows/docs/parity-matrix.md`; CI workflows are `pr-windows.yaml` / `ci-main-windows.yaml`), and `clients/chrome-extension/` (MV3 Chrome browser extension). See [`clients/README.md`](clients/README.md) and [`clients/AGENTS.md`](clients/AGENTS.md).
- `assistant/` — Main backend service (Bun + TypeScript)
- `cli/` — Multi-assistant management CLI (Bun + TypeScript). See `cli/AGENTS.md`.
- `gateway/` — Channel ingress gateway (Bun + TypeScript)
- `packages/` — Shared internal packages (e.g. `service-contracts` for CES wire-protocol schemas)
- `scripts/` — Utility scripts
- `skills/` — First-party skill catalog (portable skill packages). See `skills/AGENTS.md` for contribution rules and portability requirements.
- `.claude/` — Claude Code slash commands and helper scripts (see `.claude/README.md`). Most commands are shared from [`claude-skills`](https://github.com/vellum-ai/claude-skills) via symlinks; repo-local commands (`/update`, `/release`) live in `.claude/skills/<name>/` as local skill directories. The `/update` command uses `vellum ps`, `vellum sleep`, and `vellum wake` to manage assistant lifecycle.
- Evals have moved to a dedicated repo: [vellum-ai/evals](https://github.com/vellum-ai/evals).

**`meta/` is a parent package, NOT a shared package.** Its purpose is to be the root workspace that all service packages (`gateway/`, `assistant/`, etc.) descend from — it provides workspace-level tooling, CI configuration, and build scripts. It must never contain runtime code, constants, or configuration files that child services import. A gateway or assistant module importing from `../../meta/` is a layering violation. Static config files (e.g. allowlists, registries) that a service consumes at runtime belong in that service's own package directory. Existing `meta/` contents (feature flags, test infra) are either shared build/CI metadata or are being migrated out.

## Intellectual Honesty

Defend technical positions with evidence. Don't flip-flop to placate the user — explain what new information changed your mind, or hold the position. When recommending, consider trade-offs and failure modes before presenting; vague suggestions waste time.

## Development

- **Bun PATH**: Run `export PATH="$HOME/.bun/bin:$PATH"` before any bun/bunx commands.
- **Imports**: Packages that compile to JS (`assistant/`, `gateway/`, `cli/`) use NodeNext module resolution with `.js` extensions on all imports. Bundler-only packages (`clients/web/`, `packages/design-library/`) use `moduleResolution: "Bundler"` and omit `.js` extensions.
- **Package manager**: This is a bun workspace. One root `bun.lock` covers every member (services, `packages/*`, `clients/web`, `clients/macos`, `clients/linux`, `clients/windows`). Run `bun install` anywhere in the tree (it resolves to the workspace root), or scope it with name filters like `--filter=@vellumai/assistant` (path filters resolve against the cwd, so avoid them). Cross-package deps use `workspace:*`; `overrides`, `patchedDependencies`, and `trustedDependencies` are honored only in the root manifest. Non-member `clients/chrome-extension` keeps its own lockfile; skills carry no manifest or lockfile by design, so Bun auto-installs their pinned imports (see `skills/AGENTS.md`).
- **Windows subprocesses**: Every subprocess that can run inside the packaged Windows client, local assistant, first-party skills, or `clients/windows` tooling must set `windowsHide: true`. This applies to Node child process APIs and `Bun.spawn` / `Bun.spawnSync`. The terminal-facing launcher in `clients/windows/scripts/launch-cli.ts` is the exception because it must preserve normal CLI console behavior.

```bash
bun install                          # Install workspace dependencies (any directory works)
cd assistant && bunx tsc --noEmit    # Type-check
cd assistant && bun run typecheck:fast  # Fast type-check using tsgo
cd assistant && bun test src/path/to/changed.test.ts  # Run tests
cd assistant && bun run lint         # Lint
```

## Dependencies

This project is licensed under MIT. All dependencies must have MIT-compatible licenses (MIT, Apache-2.0, ISC, BSD-2-Clause, BSD-3-Clause, Unlicense, or similar permissive licenses). Do not add dependencies with copyleft licenses (GPL, AGPL, LGPL, SSPL, EUPL) or proprietary/restrictive licenses without explicit approval.

**Version pinning**: Always use exact versions in `dependencies` and `devDependencies` — no `^` or `~` prefixes. Use `bun add --exact` (or `bun add -E`) when adding packages. The root `bunfig.toml` sets `[install] exact = true` to enforce this by default (bun walks parent directories, so it applies to all packages). **Exception — `peerDependencies`**: Peer deps express compatibility constraints, not installation targets. Use `>=` ranges (e.g. `"react": ">=19.0.0"`) so the consuming app's lockfile controls the resolved version. See [npm docs on peer dependencies](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#peerdependencies) and [Bun docs on `--exact`](https://bun.sh/docs/cli/add#exact).

When adding a new dependency:

1. Check its license in the package's `package.json` or LICENSE file.
2. Dual-licensed packages (e.g. "MIT OR GPL-3.0") are acceptable — we use them under the MIT-compatible option.
3. If unsure about compatibility, flag it in the PR for review.
4. Verify the version in `package.json` is pinned to an exact version (no `^` or `~`).

### Pinning rules

Pin everything that has a version, with the immutable form when one exists:

- **GitHub Actions `uses:`** — pin to a 40-char commit SHA with a trailing `# vX.Y.Z` comment. Look up SHAs via `gh api repos/<owner>/<repo>/commits/<tag> --jq .sha`. For actions that only tag bare majors, use `# vN`.
- **Swift SPM** (`Package.swift`) — `.package(url: ..., exact: "X.Y.Z")`. Never `from:` (silently bumps minor/patch).
- **Dockerfile `FROM`** — exact tag plus `@sha256:` digest.
- **Bun toolchain** — `.tool-versions`, `setup.sh`, all workflow `bun-version:` inputs, and every production Dockerfile bun install must share the same exact version.
- **Node toolchain** — `.nvmrc` and every workflow `node-version:` input must share the same exact version. Intentionally separate from Bun.

We do **not** pin: `apt-get` packages (Debian rotates), `brew install` formulae (local-only), Xcode point releases, or GitHub-hosted runner system libs.

### Workflow duplication

`dev-release.yaml` and `release.yml` share inline logic (e.g. "Compute migration ceilings"). When changing logic that lives in both, update both in the same PR.

### Docker build cache

Docker `cache-to: type=gha` must set `ignore-error=true`. The GHA cache is a build-speed optimization, not part of the artifact, so a cache-export failure (e.g. `error writing layer blob: not_found` from an evicted scope) must never fail the build-push step or gate a release. See [Docker cache backends](https://docs.docker.com/build/cache/backends/).

### iOS release

The Capacitor iOS source-of-truth lives in [`clients/ios/`](./clients/ios/) and is built locally from `clients/web/` via `bun run ios:open`. See [`clients/ios/README.md`](./clients/ios/README.md) for the local build flow and full release pipeline mapping.

TestFlight builds are produced by the `release-ios.yaml` reusable workflow in this repo. Both `dev-release.yaml` and `release.yml` call it as a same-repo `uses:` job with `{ environment, version }` inputs. The workflow runs on `macos-15`, installs web dependencies, runs `cap sync ios`, generates the Xcode project via XcodeGen, archives, signs, and uploads to TestFlight.

## Cutting Releases

**Never cut or promote a release automatically. Always get explicit manual confirmation from the user first.** This applies to both release steps: dispatching `create-release-branch.yml` (branch cut + staging bake) and dispatching `release.yml` on a `release/v<X.Y.Z>` branch (production deploy). An explicit user request for the release in the current conversation counts as confirmation; otherwise ask and wait. Never dispatch either workflow as a side effect of other work (merging PRs, completing a plan, scheduled or autonomous agent runs), and standing authorizations (e.g. auto-merge) do not extend to releases. The hourly dev-release cron and the Tue/Thu branch-cut cron are disabled. Branch cuts and production promotion both require an explicit workflow_dispatch. Process details: `/release` (`.claude/skills/release/SKILL.md`).

## Testing

The full test suite is large and will hang or timeout if run unscoped. **Never run `bun test` without specifying file paths.**

- After making changes, run only the tests relevant to what you changed:
  `cd assistant && bun test src/path/to/file.test.ts`
- To run tests matching a pattern: `cd assistant && bun test src/path/to/file.test.ts --grep "pattern"`
- Use `bunx tsc --noEmit` for full-project type-checking instead of running all tests. In memory-constrained environments, use `bun run typecheck:fast` instead.
- **Regression tests for unfixed bugs**: When adding tests that reproduce a bug or document expected behavior before the fix lands, use `test.todo("description", () => {})` so mainline stays green. Never commit normally-failing `test(...)` cases — red CI blocks merges and erodes signal. Convert `test.todo` to `test` when the implementation PR lands.

## PR Workflow

- **One PR = one logical change.** Each PR is a distinct, mergeable unit of work. Keep diffs reviewable.
- **GitHub issues are for planned work, not paperwork.** When a GitHub issue already exists or the work is non-trivial enough to benefit from a separate planning artifact, link it with `Closes #N` (or `Fixes` / `Resolves`) in the PR body and commit message so GitHub [auto-closes the issue on merge](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue). Don't create retroactive issues just to satisfy a process — if the PR description already captures the _why_, that's the trace.
- **Multi-step efforts.** Use a parent issue with [sub-issues](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/adding-sub-issues) or sibling issues when the effort has multiple phases. Link intermediate PRs with `Part of #N` or `Related to #N` (no auto-close). Issues earn their keep here — they're the tracking artifact across multiple PRs.
- **Branch name**: include the issue number when one exists, e.g. `123-fix-stale-approvals`.
- **Human attention comments**: After creating a PR with non-routine changes (architectural decisions, security, complex logic, deletions, low confidence), leave a `gh pr comment` highlighting where to focus review and the risk level. Skip for routine changes.
- **Open-source hygiene**: This repo is public. Before opening a PR, review your diff for internal URLs, hardcoded credentials, proprietary infrastructure details, or references to internal services that should not be publicly visible. Generated files (OpenAPI specs, API clients) must be regenerated from committed sources — verify with `bun run generate:openapi` in `assistant/`.

### Notes for Vellum team members

When a Vellum [Linear](https://linear.app/) ticket exists for the work, link it in the PR body and include the identifier in the branch name (e.g. `lum-nnn-fix-foo`). Linear's [GitHub integration](https://linear.app/docs/github#link-using-magic-words) recognizes the same closing keywords plus non-closing words like `Part of` and `Related to` — see the linked docs for the full magic-word list and status-sync behavior. Internal slash-command and tracking-file conventions live in [`.claude/`](./.claude/) docs, not here.

## Keep Docs Up to Date

- **Internal reference**: When modifying slash commands in `.claude/skills/`, update the "Claude Code Workflow" section in `docs/internal-reference.md` to match.
- **Architecture**: When introducing, removing, or significantly modifying a service/module/data flow, update `ARCHITECTURE.md` and impacted domain docs. Mermaid diagrams must reflect current architecture.
- **AGENTS.md**: When a PR establishes a new mandatory pattern or architectural constraint, update `AGENTS.md`. Only for project-wide rules — use code comments for module-scoped patterns.

## Worktrees & Source Control

Never commit worktree directories or worktree artifacts. Git worktrees are local working copies and must remain local. The `.gitignore` already excludes common patterns (`worktrees/`, `.worktrees/`, `.codex-worktrees/`, `*-worktrees/`); if a tool creates worktree directories under a new prefix, add the pattern to `.gitignore` before committing.

## Single Source of Truth

Don't copy-paste logic. Duplicated logic drifts: a bug gets fixed in one copy and left in the others, and the copies diverge silently over time. When the same behavior (a derivation, formatter, guard, validation, fetch/retry sequence, handler) appears in more than one place, extract it into one named function/hook/module that every caller imports — fix it once, it's fixed everywhere.

- Extract on the **second** occurrence, not the fifth — two copies is the signal, not a milestone to pass.
- Share **behavior**, not just shapes: reusing a type while re-implementing the logic around it still drifts.
- Put the extracted code at the right layer (see the package's own docs — e.g. `clients/web/docs/CONVENTIONS.md` "Top-level shared directories"): used by one area → inside it; used by two or more → a shared module. Then delete the originals in the same change.

## Dead Code Removal

Proactively remove unused code during every change. Remove code your change makes unused, clean up adjacent dead code, delete rather than comment out, check for orphaned files. Ask: "After my change, is there any code that nothing calls, imports, or references?" If yes, delete it.

**Exception — migrations**: Database and data migration files must never be deleted, even when the tables or logic they create have moved elsewhere. Migrations run sequentially on existing installs and skipping an entry breaks the chain. When a migration's responsibility has moved (e.g. a table migrated to another database), keep the file in place and add a comment documenting where the logic now lives.

## Code Comments

**Comments describe the present; PRs describe the history.** Code comments should describe what the code _is_ and _does_ right now — never how it got there, what it replaced, or what changed in a PR. History and reasoning belong in PR descriptions and commit messages, which are the permanent record of _how we got here_.

- Do NOT use temporal language: "now uses", "no longer", "was previously", "instead of the old approach", "after the refactor".
- Do NOT describe the diff: "externalUserId is not consulted", "moved from X to Y", "fix for when Z happens".
- DO describe the code in present tense: "identity is enforced via the (type, address) unique constraint".
- If a comment only makes sense to someone reading the diff, move it to the PR description.

Default to no comment — bias aggressively toward terseness and rely on good naming. Follow the commenting density of the surrounding code.

## Em Dashes

Never use em dashes (`—`). Use a period, comma, colon, parentheses, or a plain hyphen instead.

This covers everything you write: user-facing copy, code comments, documentation, commit messages, and PR descriptions.

**User-facing copy is the strict case.** The assistant's own system prompt already forbids em dashes (`assistant/src/prompts/templates/SOUL.md`), so a UI string that uses one is written in a different voice from the assistant standing next to it. Treat any string a user can read (product copy, error messages, notifications, seeded prompts, API descriptions) as a hard no.

Existing text is not swept retroactively. Fix em dashes on lines you are already changing and leave the rest alone.

## Unknown Data Validation

Validate structured data from unknown boundaries with Zod before accessing its fields. This includes parsed JSON, HTTP response bodies, persisted blobs, and `unknown` tool or plugin inputs. Define a schema for the complete structure the caller consumes, call `safeParse`, check `success`, and use `parsed.data`. Do not use `as` assertions to manufacture a trusted object shape or pair handwritten `typeof` / null / array checks with asserted property access.

Keep local variables when they avoid at least one repeated operation or when inlining would produce equal or greater code or line overhead. A one-use assignment is not cleanup slop when it saves work or keeps the code smaller and clearer.

## Control-Flow Braces

Wrap every `if` / `else` / `for` / `while` / `do…while` body in braces, even a single-statement one-liner. Braces make control flow easy to scan — the block boundary is explicit — and close a common footgun: a second line added under a braceless condition reads as if it sits inside the branch but runs unconditionally. The ESLint `curly` rule enforces this at `error` in both `assistant/` and `clients/web/`; it is fully auto-fixable with `eslint --fix`.

## Generic Examples

Signals

Stars
1,449
Forks
216
Open issues
56
Last commit (this folder)
Oct 20, 2026 (9 days ago)
Last release
Sep 29, 2026 (29 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from vellum-ai

Cite this page

AGENTS.md · vellum-ai/vellum-assistant. Agent Mart. https://agentmart.dev/templates/vellum-ai-vellum-assistant-agents-md (last updated 2026-10-24)