---
title: Automatic setup
description: What `veefore` finds in your project, what it creates, how it changes your code, and how to do any part of it by hand instead.
label: Automatic setup
---

`veefore`, run in an agent project with no command, does the whole integration:
sign in, scan, set up, change the code, verify. Each step shows what it is about
to do and asks before doing it. Each is also a command of its own, so you can
run, skip or repeat any part.

| Step | Command on its own | Changes anything? |
| --- | --- | --- |
| Sign in through the browser | `veefore login` | Stores a session token |
| Scan the project | `veefore scan` | No |
| Create agent, tools, policy | `veefore init` | In Veefore, after you confirm |
| Wrap tools in `guard()` | `veefore integrate` | Your files, after you confirm |
| Verify | `veefore integrate --check` | No |
| Reverse the code change | `veefore undo` | Restores your files |
| Take Veefore out entirely | `veefore remove` | Your files, then disconnects the project |

## The scan

Static and local. The project's code is read, never run, and nothing is sent
anywhere.

**Frameworks recognised:** Vercel AI SDK, OpenAI function tools, OpenAI Agents
SDK (TypeScript and Python), LangChain.js and LangChain, CrewAI, and MCP
servers in both languages.

**No framework:** tools written as plain data, the way you hand them to a model
yourself: an object or dict with `name`, `description` and an input schema
(`parameters`, `input_schema` or `inputSchema`), in TypeScript, JavaScript or
Python. All three keys must be on the same object, so a config block that only
has a `name` is not mistaken for a tool.

For each tool it reports:

- **The external hosts it calls**, from `fetch`, `axios`, `requests`, `httpx`
  and base-URL assignments. LLM provider endpoints are recognised as the model's
  and left out. These become the tool's destination allowlist.
- **The credentials it reads**, by environment variable name only. Model keys
  such as `OPENAI_API_KEY` are listed separately and never touched.
- **A risk level**, from the tool's name. A high-impact word anywhere
  (`refund`, `delete`, `transfer`, `deploy`, …) makes it `HIGH` and `dangerous`.
  Otherwise the leading verb decides: `lookupOrder` reads, `placeOrder` writes.
  Unknown intent is `MEDIUM`, never `LOW`. A risk the definition states itself
  (`risk: 'critical'`) can raise the rating but never lower it.

What it will not do: open `.env` or any other hidden file, read a secret value,
or descend into `node_modules`, virtualenvs, build output or tests.

```bash
veefore scan          # what setup would find, without signing in
veefore scan --json   # the scan and the plan it implies, for scripts
```

Detection is pattern-based and can miss an unusual definition. Anything it
misses can be registered in the console under **Tools**.

## What setup creates

After one confirmation, through the same public API the console uses:

1. **A capability per tool**, `tool.<key>`, so authorizing one tool grants
   nothing else. Existing ones are reused.
2. **The agent**, with an Ed25519 key pair generated on your machine. Only the
   public key is sent; the private key goes to `.env.local` and nowhere else.
3. **Each tool**, registered and then authorized for this agent only.
   Registration on its own grants nothing.
4. **A starter policy** from the safe-defaults template, bound to the workspace,
   with the environment in `OBSERVE`. Tools flagged dangerous require approval
   under it once you enforce.

Running it again in another project reuses capabilities and tools that already
exist rather than duplicating them.

### Client-executed tools

Setup registers tools as kind `CLIENT`: **Veefore decides, your code
executes**. Every call is authenticated, checked against policy, risk and
approval, and recorded; when it is permitted, `guard()` runs your function.

The credential stays in your code, so this is a control only while calls go
through `guard()`. A `CLIENT` tool cannot be given an endpoint or a brokered
credential, so it never claims more protection than it has.

To close that gap, [broker the credential](/build/broker-a-credential) and
re-register the tool as `HTTP`. Veefore then performs the call itself with a key
your agent never holds, and `guard()` returns that result without running your
function, so nothing executes twice.

## The code change

`veefore integrate` (offered automatically at the end of setup) wraps the
function that performs each registered tool.

:::tabs

:::tab TypeScript / JavaScript
```diff
+import { guard } from '@veefore/sdk';

 export const tools = {
   lookupOrder: tool({
     description: 'Look up an order',
-    execute: async ({ orderId }) => {
+    execute: guard('lookup_order', async ({ orderId }) => {
       return orders.get(orderId);
-    },
+    }),
   }),
 };
```
:::

:::tab Python
```diff
 from langchain_core.tools import tool
+from veefore import guard

 @tool
+@guard("lookup_invoice")
 def lookup_invoice(invoice_id: str) -> dict:
     """Fetch an invoice by id."""
```

`@guard` goes directly above `def`, below the framework's decorator. It uses
`functools.wraps`, so `@tool`, `@function_tool` and `@mcp.tool()` still see the
original name, signature, type hints and docstring.
:::

:::

The rules the rewrite follows:

- **Only registered tools are touched**, and only the function is wrapped. Your
  function bodies are never edited.
- **JavaScript/TypeScript: only `async` functions.** `guard()` returns a
  Promise, so wrapping a synchronous function would change what it returns.
- **It never guesses.** A tool it cannot place with certainty is listed with the
  exact change to make (see below).
- **Re-running changes nothing.** Already-guarded tools are left alone. If your
  file already uses the name `guard`, the import is aliased.

### Safety

1. You see a unified diff of every file and are asked once.
2. A baseline typecheck runs first, so errors your project already had are not
   blamed on the change.
3. Every changed file is backed up to `.veefore/backups/`.
4. Then your own checks run: the project's TypeScript compiler (`--noEmit`),
   `node --check` for plain JavaScript, or a Python syntax parse. If one newly
   fails, **every file is restored automatically**.

```bash
veefore integrate --dry-run   # show the diff, write nothing
veefore undo                  # restore the last change
```

`veefore undo` leaves alone any file you edited after the change and lists it;
`--force` restores it anyway, losing your later edits.

## Tools defined as data

When tools are plain definitions, no one function performs each tool: your code
runs whichever tool the model picked, usually in one dispatch function. One
guard there covers every tool routed through it.

`veefore integrate` finds that place and adds the guard itself when the shape
is unambiguous: a function named like `executeTool`, `runTool` or
`handle_tool_call`, whose argument carries the tool's name (`call.tool`,
`call.name`), with exactly one awaited call inside that receives it.

```diff
+import { guard } from '@veefore/sdk';
 …
 export async function executeTool(call: ToolCall): Promise<ToolResult> {
   …
-  result = await executor.execute(call);
+  result = await guard(call.tool, (_args: typeof call.params) => executor.execute(call))(call.params);
```

It goes through the same diff, backup, typecheck and rollback as every other
change. In a monorepo, each changed file is typechecked by its own package's
`tsconfig.json`.

When the place is found but the shape is not certain, or the project is Python,
you get the same three choices as below: make the change by hand from exact
instructions naming the file and function, or have AI make it with your own key
or with Veefore AI. An AI change here is accepted only if it adds a single
guard keyed by the tool name and nothing else.

:::tabs

:::tab TypeScript / JavaScript
```ts
import { guard } from '@veefore/sdk';

// before:  const result = await runTool(call);
const result = await guard(call.name, (_args: typeof call.args) => runTool(call))(call.args);
```
:::

:::tab Python
```python
from veefore import guard

# before:  result = run_tool(call.name, call.args)
result = guard(call.name, describe=lambda _args: {"parameters": _args})(
    lambda _args: run_tool(call.name, call.args))(call.args)
```
:::

:::

The first argument must be the tool's Veefore key, which is its name when that
is `lower_snake_case`. A refusal throws, so the guard belongs where your code
already turns errors into a tool result for the model.

`veefore integrate --check` then reports those tools as guarded at the
dispatch point. It checks that the guard exists, not that every path reaches
it, so keep it where every tool call passes.

## Tools the rewrite will not change

A method-style `execute`, a synchronous function, an OpenAI tool that is only a
schema, or LangChain `Tool(func=…)`. For these you choose:

```
How would you like to handle them?
  1  I will change them myself (show me exactly what to change)
  2  Use AI with my own Anthropic or OpenAI key (code goes only to that provider)
  3  Use Veefore AI (code is sent to Veefore, then to its model provider)
  4  Skip for now
```

Or choose up front with `--assist=manual`, `--assist=own`, `--assist=veefore`
or `--assist=off`. Without a terminal to ask, the default is `manual`.

### By hand

Nothing is sent anywhere. For each tool you get the file, the line, the import
to add and the exact code to change it to:

```
src/agent.ts
  Add once, with the other imports:
    import { guard } from '@veefore/sdk';

  lookup_order  near line 8 — execute is written as a method
    // before:  async execute(args) { … }
    execute: guard('lookup_order', async (args) => { … }),
```

When you are done:

```bash
veefore integrate --check
```

It lists every registered tool as guarded or not, and exits `1` if any are not,
so it also works as a CI check.

### With AI

Both AI options work the same way:

- **Secrets are replaced with placeholders** before anything leaves your
  machine, and restored locally afterwards: provider keys (Stripe, OpenAI,
  Anthropic, AWS, GitHub, Slack, Google), JWTs, passwords inside URLs, private
  keys, and random-looking string literals.
- **You see what is sent and to whom, and must agree:** which files, the
  destination, the model, and how many secrets were removed. Only the files
  that need the change are sent.
- **The reply is untrusted.** It is accepted only if it keeps every token of
  your file, adds no new string, adds almost nothing beyond the `guard()` change
  and actually guards the requested tools. A rejected or declined reply falls
  back to the manual instructions.
- **An accepted change is marked "proposed by AI"** in the diff and goes through
  the same confirmation, backup, checks and rollback as everything else.

**Your own key.** Uses `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` from your shell,
or a key you paste, held in memory for that run only. It lists the models your
key can use and you pick one (`VEEFORE_AI_MODEL` preselects). Your code goes from
your machine straight to that provider, never through Veefore.

```bash
ANTHROPIC_API_KEY=… veefore integrate --assist=own
```

**Veefore AI.** Available when it is enabled for your Veefore, with the models
its operator chose. Your code goes to Veefore and then to its model provider. It is
used for that request only and never stored or logged; the audit trail records
who asked, which model, which tools and the file size. Rate limited per person.

## Removing Veefore from a project

```bash
veefore remove --dry-run   # show what would change
veefore remove
```

It offers to revoke the agent if it is still active, takes every `guard()`
back out of the code, and then disconnects the project by deleting
`veefore.config.json` and the Veefore block in `.env.local`, including the
private key. The code change gets the same diff, confirmation, backup, checks
and rollback as adding it. Unlike `veefore undo`, it rewrites the code instead
of restoring an old copy, so edits you made after setup are kept.

**Revoked in the console?** The console cannot change files on a developer's
machine, so revoking an agent there stops it at once, and every guarded call is
refused from then on, but leaves the code as it is. The next time anyone runs
`veefore` in that project, it notices and offers two ways forward: remove
Veefore from the code, or set the project up again with a new agent. The
guarded code keeps working with the new agent, because the tool keys are the
same. `veefore integrate` refuses to add guards for a revoked agent and points
at the same two options.

## Running `veefore` again

In a project that is already connected, `veefore` shows the agent, the
environment and the agent's status in Veefore, then offers: check status,
protect tools in the code, re-run setup, remove Veefore from the project, or
sign out.

## Related

:::cards

:::card Protect an agent | /build/protect-an-agent
guard() and the client surface in full.
:::

:::card Register a tool | /build/register-a-tool
Every tool kind, including CLIENT and HTTP.
:::

:::card Broker a credential | /build/broker-a-credential
The step that makes skipping the SDK useless.
:::

:::card CLI reference | /reference/cli
Every command and option. Generated.
:::

:::
