Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
.git
test
specs
deploy
website
data
dist
.claude
.specify
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@
# III_STREAMS_PORT=3112 # Streams API port
# III_ENGINE_URL=ws://localhost:49134 # iii-engine WebSocket URL (used by the worker)

# AGENTMEMORY_MCP_PORT=3114 # MCP Streamable HTTP port (JSON-RPC transport). Defaults to REST port + 3.
# # MCP clients that speak Streamable HTTP can connect directly to
# # http://localhost:3114/mcp instead of spawning npx @agentmemory/mcp.

# -----------------------------------------------------------------------------
# 8. iii engine pin
# -----------------------------------------------------------------------------
Expand Down
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
ARG III_VERSION=0.11.2

FROM node:22-slim AS build
WORKDIR /app
COPY package.json package-lock.json tsconfig.json tsdown.config.ts ./
RUN npm ci
COPY src/ ./src/
RUN npm run build

FROM iiidev/iii:${III_VERSION} AS iii-image

FROM node:22-slim AS runtime
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tini curl \
&& rm -rf /var/lib/apt/lists/*
ARG III_VERSION
COPY --from=iii-image /app/iii /usr/local/bin/iii
WORKDIR /app
COPY --from=build /app/dist/ ./dist/
COPY --from=build /app/package.json /app/package-lock.json ./
RUN npm ci --omit=dev --no-fund --no-audit
# Fallback default config; entrypoint.sh overwrites this for Docker at startup
COPY iii-config.docker.yaml ./iii-config.yaml
COPY entrypoint.sh ./
RUN chmod +x entrypoint.sh
EXPOSE 3111 3112 3113 3114
ENTRYPOINT ["/usr/bin/tini", "--", "/app/entrypoint.sh"]
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,49 @@ Imported sessions show up in the Replay picker alongside native ones. Under the

> **Heads-up if you rely on `import-jsonl` as your primary capture path:** Claude Code's `cleanupPeriodDays` (in `~/.claude/settings.json`, default **30**) auto-deletes JSONL transcripts older than that window from `~/.claude/projects/`. If you install agentmemory fresh on a months-old Claude Code history, anything older than 30 days is already gone before the first import. Either run `import-jsonl` on a cron, raise `cleanupPeriodDays` to something higher, or wire the auto-capture hooks (the default plugin install path) so each turn lands in agentmemory while the session is live and the JSONL cleanup stops mattering.

### Docker

Run agentmemory in a container with one command — no Node.js or npm required on the host.

**Prerequisites:** Docker and docker-compose.

```bash
# Clone and start — iii engine + agentmemory worker + viewer + MCP Stream HTTP
git clone https://github.com/rohitg00/agentmemory.git
cd agentmemory
docker compose build && docker compose up -d

# Grab the auto-generated HMAC secret for MCP client auth
docker compose logs agentmemory | grep AGENTMEMORY_SECRET
# or: docker compose exec agentmemory cat /data/.hmac

# Verify it is up
curl -s http://localhost:3111/agentmemory/health | head -c 200
```

MCP clients that speak Streamable HTTP can connect directly without spawning
an `npx` process:

```json
{
"mcpServers": {
"agentmemory": {
"url": "http://localhost:3114/mcp",
"headers": {
"Authorization": "Bearer <secret-from-/data/.hmac>"
}
}
}
}
```

Stdio-based MCP clients (Cursor, Claude Code, etc.) still work through the
`npx @agentmemory/mcp` shim as usual — set `AGENTMEMORY_URL=http://localhost:3111`
and `AGENTMEMORY_SECRET` in the client's env block.

See [specs/001-mcp-stream-dockerize/quickstart.md](specs/001-mcp-stream-dockerize/quickstart.md)
for advanced Docker setups (custom ports, external volumes, multi-instance).

### Upgrade / Maintenance

Use the maintenance command when you intentionally want to update your local runtime:
Expand Down
54 changes: 39 additions & 15 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
services:
# One-shot init container: docker creates named volumes root:root mode
# 755, but the iii-engine image is distroless and runs as UID 65532
# with no `chown` of its own. Without this, /data is unwritable, the
# engine silently buffers in RAM, and state evaporates on every
# restart — the exact symptom v0.9.7's working-directory fix set out
# to solve. Runs once at compose-up and exits.
iii-init:
image: busybox:1.36
user: "0:0"
Expand All @@ -14,15 +8,6 @@ services:
restart: "no"

iii-engine:
# Pinned to v0.11.2 — the last engine that runs agentmemory's current
# worker model cleanly. v0.11.6 introduces a new sandbox-everything-
# via-`iii worker add` model that agentmemory hasn't been refactored
# for yet; the architectural mismatch surfaces as EPIPE reconnect
# loops and empty search after save. Bump only after agentmemory is
# refactored to register as a sandboxed worker.
#
# Override per-shell or via .env file:
# AGENTMEMORY_III_VERSION=0.11.7 docker compose up
image: iiidev/iii:${AGENTMEMORY_III_VERSION:-0.11.2}
user: "65532:65532"
depends_on:
Expand All @@ -36,6 +21,45 @@ services:
volumes:
- iii-data:/data
- ./iii-config.docker.yaml:/app/config.yaml:ro
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3111/agentmemory/livez"]
interval: 5s
timeout: 3s
retries: 10
start_period: 5s
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"

agentmemory:
build:
context: .
dockerfile: Dockerfile
args:
III_VERSION: ${AGENTMEMORY_III_VERSION:-0.11.2}
depends_on:
iii-engine:
condition: service_healthy
ports:
- "127.0.0.1:3114:3114"
- "127.0.0.1:3113:3113"
volumes:
- iii-data:/data
environment:
AGENTMEMORY_TOOLS: all
AGENTMEMORY_SECRET_FILE: /data/.hmac
III_ENGINE_URL: ws://iii-engine:49134
III_REST_PORT: "3111"
AGENTMEMORY_MCP_PORT: "3114"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3111/agentmemory/livez"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
restart: unless-stopped
logging:
driver: json-file
Expand Down
78 changes: 78 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/bin/sh
set -eu

DATA_DIR="${AGENTMEMORY_DATA_DIR:-/data}"
HMAC_FILE="${AGENTMEMORY_HMAC_FILE:-/data/.hmac}"

mkdir -p "$DATA_DIR"
chown -R node:node "$DATA_DIR"

if [ ! -s "$HMAC_FILE" ]; then
SECRET="$(openssl rand -hex 32)"
umask 077
printf '%s\n' "$SECRET" > "$HMAC_FILE"
chmod 600 "$HMAC_FILE"
chown node:node "$HMAC_FILE"
echo "Generated new AGENTMEMORY_SECRET"
fi

if [ -z "${AGENTMEMORY_SECRET_FILE:-}" ]; then
export AGENTMEMORY_SECRET_FILE="$HMAC_FILE"
fi

cat > /app/iii-config.yaml <<'EOF'
workers:
- name: iii-http
config:
port: 3111
host: 0.0.0.0
default_timeout: 180000
cors:
allowed_origins:
- "http://localhost:3111"
- "http://localhost:3113"
- "http://localhost:3114"
- "http://127.0.0.1:3111"
- "http://127.0.0.1:3113"
- "http://127.0.0.1:3114"
allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
- name: iii-state
config:
adapter:
name: kv
config:
store_method: file_based
file_path: /data/state_store.db
- name: iii-queue
config:
adapter:
name: builtin
- name: iii-pubsub
config:
adapter:
name: local
- name: iii-cron
config:
adapter:
name: kv
- name: iii-stream
config:
port: 3112
host: 0.0.0.0
adapter:
name: kv
config:
store_method: file_based
file_path: /data/stream_store
- name: iii-observability
config:
enabled: true
service_name: agentmemory
exporter: memory
sampling_ratio: 0.1
metrics_enabled: true
logs_enabled: true
logs_console_output: false
EOF

exec node /app/dist/index.mjs
8 changes: 1 addition & 7 deletions iii-config.docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ workers:
host: 0.0.0.0
default_timeout: 180000
cors:
allowed_origins: ["http://localhost:3111", "http://localhost:3113", "http://127.0.0.1:3111", "http://127.0.0.1:3113"]
allowed_origins: ["http://localhost:3111", "http://localhost:3113", "http://localhost:3114", "http://127.0.0.1:3111", "http://127.0.0.1:3113", "http://127.0.0.1:3114"]
allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
- name: iii-state
config:
Expand Down Expand Up @@ -45,9 +45,3 @@ workers:
metrics_enabled: true
logs_enabled: true
logs_console_output: false
- name: iii-exec
config:
watch:
- src/**/*.ts
exec:
- node dist/index.mjs
6 changes: 2 additions & 4 deletions plugin/scripts/notification.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
import { execSync } from "node:child_process";
import { basename } from "node:path";

//#region src/hooks/_project.ts
function resolveProject(cwd) {
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
Expand All @@ -21,7 +20,6 @@ function resolveProject(cwd) {
} catch {}
return basename(dir);
}

//#endregion
//#region src/hooks/notification.ts
function isSdkChildContext(payload) {
Expand Down Expand Up @@ -70,7 +68,7 @@ async function main() {
setTimeout(() => process.exit(0), 500).unref();
}
main();

//#endregion
export { };
export {};

//# sourceMappingURL=notification.mjs.map
5 changes: 2 additions & 3 deletions plugin/scripts/post-commit.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
import { execFile } from "node:child_process";
import { promisify } from "node:util";

//#region src/hooks/post-commit.ts
const exec = promisify(execFile);
function isSdkChildContext(payload) {
Expand Down Expand Up @@ -96,7 +95,7 @@ async function main() {
} catch {}
}
main();

//#endregion
export { };
export {};

//# sourceMappingURL=post-commit.mjs.map
6 changes: 2 additions & 4 deletions plugin/scripts/post-tool-failure.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
import { execSync } from "node:child_process";
import { basename } from "node:path";

//#region src/hooks/_project.ts
function resolveProject(cwd) {
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
Expand All @@ -21,7 +20,6 @@ function resolveProject(cwd) {
} catch {}
return basename(dir);
}

//#endregion
//#region src/hooks/post-tool-failure.ts
function isSdkChildContext(payload) {
Expand Down Expand Up @@ -71,7 +69,7 @@ async function main() {
setTimeout(() => process.exit(0), 500).unref();
}
main();

//#endregion
export { };
export {};

//# sourceMappingURL=post-tool-failure.mjs.map
6 changes: 2 additions & 4 deletions plugin/scripts/post-tool-use.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
import { execSync } from "node:child_process";
import { basename } from "node:path";

//#region src/hooks/_project.ts
function resolveProject(cwd) {
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
Expand All @@ -21,7 +20,6 @@ function resolveProject(cwd) {
} catch {}
return basename(dir);
}

//#endregion
//#region src/hooks/post-tool-use.ts
function isSdkChildContext(payload) {
Expand Down Expand Up @@ -116,7 +114,7 @@ function truncate(value, max) {
return value;
}
main();

//#endregion
export { };
export {};

//# sourceMappingURL=post-tool-use.mjs.map
6 changes: 2 additions & 4 deletions plugin/scripts/pre-compact.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node
import { execSync } from "node:child_process";
import { basename } from "node:path";

//#region src/hooks/_project.ts
function resolveProject(cwd) {
const explicit = process.env["AGENTMEMORY_PROJECT_NAME"];
Expand All @@ -21,7 +20,6 @@ function resolveProject(cwd) {
} catch {}
return basename(dir);
}

//#endregion
//#region src/hooks/pre-compact.ts
function isSdkChildContext(payload) {
Expand Down Expand Up @@ -74,7 +72,7 @@ async function main() {
} catch {}
}
main();

//#endregion
export { };
export {};

//# sourceMappingURL=pre-compact.mjs.map
Loading