bun install
bun run pg
# configure .env (see below)
bun run setup
bun run server
# in another terminal:
bun run packages/cli/index.ts --server http://localhost:3000 loginbun installThe project requires PostgreSQL 18 with three extensions: pgvector, pg_textsearch, and ltree. The included Dockerfile builds a pre-configured image:
bun run pgThis builds the Docker image and starts a container named me-postgres on localhost:5432 with trust authentication (no password).
Other database commands:
| Command | Description |
|---|---|
bun run pg:rm |
Stop and remove the container |
bun run psql |
Connect with psql |
Copy the sample and fill in the required values:
cp .env.sample .envDatabase connections — both point to the local Docker Postgres, but use separate databases:
ACCOUNTS_DATABASE_URL=postgres://postgres@localhost:5432/accounts
ENGINE_DATABASE_URL=postgres://postgres@localhost:5432/shard1
Encryption master key — 32-byte hex string for encrypting API keys at rest:
bun run generate:master-keyPaste the output into .env:
ACCOUNTS_MASTER_KEY=<output from above>
Server URL and port — API_BASE_URL is used to construct OAuth callback URLs. PORT controls which port the server listens on. They must be consistent:
API_BASE_URL=http://localhost:3000
PORT=3000
If you change the port (e.g. because something else is on 3000), update both:
API_BASE_URL=http://localhost:3132
PORT=3132
Embedding API key — an OpenAI API key (or compatible provider):
EMBEDDING_API_KEY=sk-...
Google:
- Go to Google Cloud Console > Credentials
- Create an OAuth client ID (Web application)
- Add authorized redirect URI:
http://localhost:<PORT>/api/v1/auth/callback/google - Copy the client ID and secret:
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GitHub:
- Go to GitHub Developer Settings
- Create a new OAuth App
- Set the callback URL to:
http://localhost:<PORT>/api/v1/auth/callback/github - Copy the client ID and secret:
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
The redirect URI must match your
API_BASE_URLexactly, including the port.
# Database
ACCOUNTS_DATABASE_URL=postgres://postgres@localhost:5432/accounts
ENGINE_DATABASE_URL=postgres://postgres@localhost:5432/shard1
ACCOUNTS_MASTER_KEY=<bun run generate:master-key>
# Server
API_BASE_URL=http://localhost:3000
PORT=3000
# Embedding
EMBEDDING_API_KEY=sk-...
# OAuth (at least one)
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
# Telemetry (optional) — omit to disable
# LOGFIRE_TOKEN=...
# LOGFIRE_ENVIRONMENT=devbun run setupThis is idempotent (safe to run multiple times) and will:
- Create the
accountsandshard1databases if they don't exist - Run account schema migrations
- Create and activate an encryption data key
- Bootstrap the engine database (extensions and roles)
bun run serverIn another terminal:
bun run packages/cli/index.ts --server http://localhost:3000 loginOr set ME_SERVER to avoid passing --server every time:
export ME_SERVER=http://localhost:3000
bun run packages/cli/index.ts loginAfter login, the server URL is stored as the default in ~/.config/me/credentials.yaml, so subsequent commands don't need --server.
| Command | Description |
|---|---|
bun run server |
Start the server |
bun run setup |
Create databases, run migrations, bootstrap engine |
bun run pg |
Build and start PostgreSQL in Docker |
bun run pg:rm |
Stop and remove the PostgreSQL container |
bun run psql |
Connect to PostgreSQL with psql |
bun run test |
Run tests |
bun run check |
Format + lint + typecheck |
bun run build |
Compile CLI binary (current platform) |
bun run build:all |
Cross-compile CLI for all platforms |
bun run install:local |
Build and install local CLI binary to your PATH |
bun run clean |
Remove build artifacts |
bun run generate:master-key |
Generate a new encryption master key |
bun run release:client |
Cut a client release (CLI + npm packages) |
bun run release:server |
Cut a server release (deploys to prod) |
The client (CLI, npm packages) and the server (deployed container) are released independently. They carry separate version counters, use separate tag prefixes, and are triggered by separate scripts.
| Constant | Source of truth | Exposed via |
|---|---|---|
CLIENT_VERSION |
root package.json |
me --version, MCP handshake, npm-published packages |
SERVER_VERSION |
packages/server/package.json |
Logfire serviceVersion, migration applied_at_version and <schema>.version, gitRevision fallback in prod |
Both are exported from version.ts. Migration tracking — including the
downgrade-rejection guard in the runners — uses SERVER_VERSION, so the
DB's recorded version advances only when the server is released.
bun run release:client — bumps the version in:
package.jsonpackages/cli/package.jsonpackages/client/package.jsonpackages/protocol/package.json
Commits, creates an annotated tag v<version>, and pushes.
The v* tag triggers .github/workflows/release.yml, which:
- Publishes
@memory.build/protocoland@memory.build/clientto npm. - Builds the
meCLI for all platforms. - Creates a GitHub Release with the binaries.
- Publishes the CLI wrapper to npm.
- Updates the Homebrew formula.
bun run release:server — bumps the version in the server-side packages
in lockstep:
packages/accounts/package.jsonpackages/embedding/package.jsonpackages/engine/package.jsonpackages/server/package.json(canonical source)packages/worker/package.json
Commits, creates an annotated tag server/v<version>, and pushes.
The server/v* tag triggers .github/workflows/deploy-prod.yaml, which
builds the server image from packages/server/Dockerfile and deploys it
to prod.
The dev environment is redeployed automatically by
.github/workflows/deploy-dev.yaml on every push to main that touches a
server path — no tag required.
bun run release:client 0.2.0 # explicit version
bun run release:client patch # 0.1.16 -> 0.1.17
bun run release:client minor # 0.1.16 -> 0.2.0
bun run release:client # prompts for version
bun run release:server patch # same arg shapes; tags server/v<...>Both scripts require:
- Clean working tree, on
main, up to date withorigin/main. - Version strictly greater than the current one.
- Tag doesn't already exist.
- Explicit
yconfirmation at the prompt.
Because the client and server release independently, the typical sequence for a change that spans both sides is:
- Land a backwards-compatible server change on
main. Dev auto-deploys. bun run release:serverto tagserver/v<next>and deploy prod.- Land the client change on
mainthat depends on the new server behavior. bun run release:clientto publish the CLI and npm packages.
The server counter and the client counter will diverge over time — that's expected. They're not related after this split.
Database migrations run at server startup using SERVER_VERSION as the
serverVersion passed to the runners. When you add a new migration file under
packages/engine/migrate/migrations/ or packages/accounts/migrate/migrations/:
- Cut a server release afterwards (
bun run release:server) to advanceSERVER_VERSIONand propagate the migration to prod. - The migration's
applied_at_versioncolumn and the schema'sversionrow will reflect the newSERVER_VERSION. - Rolling back to an older server image will then trip the downgrade guard in the migration runners — by design.
CLI says "Failed to start device flow: HTTP 405"
The CLI defaults to http://localhost:3000. If your server is on a different port, pass --server http://localhost:<PORT> or set ME_SERVER.
Google OAuth "redirect_uri_mismatch"
The redirect URI registered in Google Cloud Console must exactly match <API_BASE_URL>/api/v1/auth/callback/google, including the port.
API_BASE_URL vs PORT
PORT controls where the server listens. API_BASE_URL is used to build OAuth callback URLs sent to providers. If they don't match, OAuth callbacks will fail.