Skip to content

Deploy an agent

Deploy the agent on a Node.js host that supports environment variables and persistent storage.

VariablePurpose
XMTP_BACKEND_URLSelf-hosted backend URL, including scheme
XMTP_WALLET_KEYAgent wallet key in 0x hex format
XMTP_DB_ENCRYPTION_KEY32-byte local database encryption key
XMTP_DB_DIRECTORYPersistent directory for Agent SDK databases
XMTP_ENVOptional database file label; it does not select a backend

Agent.createFromEnv() creates XMTP_DB_DIRECTORY with owner-only permissions and stores the database there. Mount this directory on a persistent volume.

Back up these SQLite files for persistent storage:

  • {env}-{description}.db3 - Main database
  • {env}-{description}.db3-shm - Shared memory
  • {env}-{description}.db3-wal - Write-ahead log
  • {env}-{description}.db3.sqlcipher_salt - Encryption salt

Rough estimate: 1GB ≈ 15,000 conversations. Plan based on your expected volume.

For a provider that supplies RAILWAY_VOLUME_MOUNT_PATH, use a database path callback:

const
const customDbPath: (inboxId: string) => string
customDbPath
= (
inboxId: string
inboxId
: string) =>
`${
var process: NodeJS.Process
process
.
NodeJS.Process.env: NodeJS.ProcessEnv

The process.env property returns an object containing the user environment. See environ(7).

An example of this object looks like:

{
TERM: 'xterm-256color',
SHELL: '/usr/local/bin/bash',
USER: 'maciej',
PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
PWD: '/Users/maciej',
EDITOR: 'vim',
SHLVL: '1',
HOME: '/Users/maciej',
LOGNAME: 'maciej',
_: '/usr/local/bin/node'
}

It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

Terminal window
node -e 'process.env.foo = "bar"' && echo $foo

While the following will:

import { env } from 'node:process';
env.foo = 'bar';
console.log(env.foo);

Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

import { env } from 'node:process';
env.test = null;
console.log(env.test);
// => 'null'
env.test = undefined;
console.log(env.test);
// => 'undefined'

Use delete to delete a property from process.env.

import { env } from 'node:process';
env.TEST = 1;
delete env.TEST;
console.log(env.TEST);
// => undefined

On Windows operating systems, environment variables are case-insensitive.

import { env } from 'node:process';
env.TEST = 1;
console.log(env.test);
// => 1

Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

@sincev0.1.27

env
.
string | undefined
RAILWAY_VOLUME_MOUNT_PATH
?? "."}/${
var process: NodeJS.Process
process
.
NodeJS.Process.env: NodeJS.ProcessEnv

The process.env property returns an object containing the user environment. See environ(7).

An example of this object looks like:

{
TERM: 'xterm-256color',
SHELL: '/usr/local/bin/bash',
USER: 'maciej',
PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
PWD: '/Users/maciej',
EDITOR: 'vim',
SHLVL: '1',
HOME: '/Users/maciej',
LOGNAME: 'maciej',
_: '/usr/local/bin/node'
}

It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

Terminal window
node -e 'process.env.foo = "bar"' && echo $foo

While the following will:

import { env } from 'node:process';
env.foo = 'bar';
console.log(env.foo);

Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

import { env } from 'node:process';
env.test = null;
console.log(env.test);
// => 'null'
env.test = undefined;
console.log(env.test);
// => 'undefined'

Use delete to delete a property from process.env.

import { env } from 'node:process';
env.TEST = 1;
delete env.TEST;
console.log(env.TEST);
// => undefined

On Windows operating systems, environment variables are case-insensitive.

import { env } from 'node:process';
env.TEST = 1;
console.log(env.test);
// => 1

Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

@sincev0.1.27

env
.
string | undefined
XMTP_ENV
}-${
inboxId: string
inboxId
.
String.slice(start?: number, end?: number): string

Returns a section of a string.

@paramstart The index to the beginning of the specified portion of stringObj.

@paramend The index to the end of the specified portion of stringObj. The substring includes the characters up to, but not including, the character indicated by end. If this value is not specified, the substring continues to the end of stringObj.

slice
(0, 8)}.db3`;
const
const agent: Agent<BuiltInContentTypes>
agent
= await
class Agent<ContentTypes = unknown>

Event-driven XMTP agent that routes conversations and messages to middleware.

Agent
.
Agent<ContentTypes = unknown>.createFromEnv<[]>(options?: Partial<AgentCreateOptions<[]>> | undefined): Promise<Agent<BuiltInContentTypes>>

Create an agent from XMTP_* variables. XMTP_BACKEND_URL overrides options.backendUrl; one must be supplied.

createFromEnv
({
backendUrl?: string | undefined

Backend URL, including the HTTP or HTTPS scheme.

backendUrl
:
var process: NodeJS.Process
process
.
NodeJS.Process.env: NodeJS.ProcessEnv

The process.env property returns an object containing the user environment. See environ(7).

An example of this object looks like:

{
TERM: 'xterm-256color',
SHELL: '/usr/local/bin/bash',
USER: 'maciej',
PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
PWD: '/Users/maciej',
EDITOR: 'vim',
SHLVL: '1',
HOME: '/Users/maciej',
LOGNAME: 'maciej',
_: '/usr/local/bin/node'
}

It is possible to modify this object, but such modifications will not be reflected outside the Node.js process, or (unless explicitly requested) to other Worker threads. In other words, the following example would not work:

Terminal window
node -e 'process.env.foo = "bar"' &#x26;&#x26; echo $foo

While the following will:

import { env } from 'node:process';
env.foo = 'bar';
console.log(env.foo);

Assigning a property on process.env will implicitly convert the value to a string. This behavior is deprecated. Future versions of Node.js may throw an error when the value is not a string, number, or boolean.

import { env } from 'node:process';
env.test = null;
console.log(env.test);
// => 'null'
env.test = undefined;
console.log(env.test);
// => 'undefined'

Use delete to delete a property from process.env.

import { env } from 'node:process';
env.TEST = 1;
delete env.TEST;
console.log(env.TEST);
// => undefined

On Windows operating systems, environment variables are case-insensitive.

import { env } from 'node:process';
env.TEST = 1;
console.log(env.test);
// => 1

Unless explicitly specified when creating a Worker instance, each Worker thread has its own copy of process.env, based on its parent thread's process.env, or whatever was specified as the env option to the Worker constructor. Changes to process.env will not be visible across Worker threads, and only the main thread can make changes that are visible to the operating system or to native add-ons. On Windows, a copy of process.env on a Worker instance operates in a case-sensitive manner unlike the main thread.

@sincev0.1.27

env
.
string | undefined
XMTP_BACKEND_URL
,
dbPath?: string | ((inboxId: string) => string) | null | undefined

Path to the local DB

There are 4 value types that can be used to specify the database path:

  • undefined (or excluded from the client options) The database will be created in the current working directory and is based on the environment label and client inbox ID. Example: xmtp-default-<inbox-id>.db3

  • null No database will be created and all data will be lost once the client disconnects.

  • string The given path will be used to create the database. Example: ./my-db.db3

  • function A callback function that receives the inbox ID and returns a string path. Example: (inboxId) => string

dbPath
:
const customDbPath: (inboxId: string) => string
customDbPath
,
});

Use pm2-runtime when PM2 runs in a container. Set unstable_restarts: 10000 so PM2 does not stop restarts during rapid crash cycles.

For an agent to function—whether it’s answering questions, executing commands, or providing automated responses—it must be able to read the conversation to understand what’s being asked, and write messages to respond.

Like any other user, this means your agent holds the cryptographic keys required to decrypt and send messages in the conversation. As an agent developer, it’s important to uphold the security of these keys and messages.

  • Never expose private keys: Use environment variables.
  • Keep messages secure and private: Do not log messages in plaintext. Do not share messages with third parties.
  • Label agents clearly: Clearly identify your agent as an agent and don’t have an agent impersonate a human.