Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b4696e7
feat: add Pi memory integration
bluewatercg Aug 3, 2026
113e90a
fix: support root Electron dev startup
bluewatercg Aug 3, 2026
0745210
fix: disable streaming for model config probes
bluewatercg Aug 3, 2026
6dbfa84
feat: support remote Docker memory runtime
bluewatercg Aug 3, 2026
040053d
test: align desktop fixtures with component contracts
bluewatercg Aug 3, 2026
7972549
ci: prepare Windows packaging environment
bluewatercg Aug 3, 2026
cdfd705
fix: recover Windows config replacement conflicts
bluewatercg Aug 3, 2026
e2ec114
feat: expand Memory panel into standalone console
bluewatercg Aug 3, 2026
eece4b3
feat: add scoped memory governance protocol
bluewatercg Aug 5, 2026
f02ccc8
docs: document fork-specific memory updates
bluewatercg Aug 5, 2026
b38546f
feat(memory): add project-scoped review synthesis
bluewatercg Aug 5, 2026
2432877
feat: add context pack views and token usage stats
bluewatercg Aug 8, 2026
5c4ad06
feat: add context pack history and secure docker releases
bluewatercg Aug 9, 2026
25adf2e
docs: design authoritative project context pack
bluewatercg Aug 10, 2026
7de46eb
feat(memory): add authoritative project context
bluewatercg Aug 10, 2026
4dbfc27
feat(backend): expose project context governance
bluewatercg Aug 10, 2026
b7c274e
feat(agent): preserve project context turn provenance
bluewatercg Aug 10, 2026
64d559a
feat(desktop): add project context governance
bluewatercg Aug 10, 2026
305b003
docs: explain authoritative project context
bluewatercg Aug 10, 2026
80731be
fix(memory): preserve actual injected source ids
bluewatercg Aug 10, 2026
544a957
fix(desktop): preserve governance button typography
bluewatercg Aug 10, 2026
4100c22
test(backend): align runtime registry expectations
bluewatercg Aug 10, 2026
6d03352
test(backend): stabilize sqlite suites on WSL
bluewatercg Aug 10, 2026
d0915ce
Merge origin/main into project context governance
bluewatercg Aug 10, 2026
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
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.git
.github
node_modules
**/node_modules
**/dist
release
**/release
.env
.env.*
!.env.example
*.log
*.sqlite
*.sqlite-*
.memmy
.codex
.pi
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,24 @@ MEMMY_GA4_MEASUREMENT_ID=
# Legal agreement page base URLs
MEMMY_LEGAL_CN_BASE_URL=https://memmy.cn
MEMMY_LEGAL_INTL_BASE_URL=https://memmy.bot

# Docker Memory service. Generate a unique value with at least 32 random bytes.
MEMMY_MEMORY_TOKEN=
# Host-side port; keep the default for a same-machine Windows desktop client.
MEMMY_MEMORY_HOST_PORT=18960

# OpenAI-compatible project memory models. Keep the key only in local .env.
MEMMY_SUMMARY_PROVIDER=openai_compatible
MEMMY_SUMMARY_ENDPOINT=http://192.168.8.191:20128/v1
MEMMY_SUMMARY_MODEL=auto/best-fast
MEMMY_SUMMARY_API_KEY=
MEMMY_SUMMARY_MAX_TOKENS=768
MEMMY_SUMMARY_TIMEOUT_MS=60000

MEMMY_EVOLUTION_PROVIDER=openai_compatible
MEMMY_EVOLUTION_ENDPOINT=http://192.168.8.191:20128/v1
MEMMY_EVOLUTION_MODEL=auto/best-reasoning
MEMMY_EVOLUTION_API_KEY=
MEMMY_EVOLUTION_ENABLE_THINKING=true
MEMMY_EVOLUTION_MAX_TOKENS=4096
MEMMY_EVOLUTION_TIMEOUT_MS=180000
139 changes: 139 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Publish Memory Docker image

on:
push:
tags:
- "v*.*.*"
workflow_call:
inputs:
tag:
description: Image tag to publish
required: true
type: string
ref:
description: Trusted Git ref or commit to build
required: true
type: string
workflow_dispatch:
inputs:
tag:
description: Image tag to publish
required: true
default: edge
type: string
ref:
description: Git ref or commit to build
required: true
default: main
type: string

permissions:
contents: read
packages: write

concurrency:
group: memory-docker-${{ github.ref }}-${{ inputs.tag || 'tag' }}
cancel-in-progress: false

jobs:
smoke:
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build smoke image
uses: docker/build-push-action@v6
with:
context: .
file: Memory/Dockerfile
platforms: linux/amd64
load: true
tags: memmy-memory:smoke
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Run container smoke test
shell: bash
run: |
docker run -d --name memmy-memory-smoke \
-e HOME=/home/node \
-e MEMMY_MEMORY_HOST=0.0.0.0 \
-e MEMMY_MEMORY_PORT=18960 \
-e MEMMY_MEMORY_DB=/data/memory.sqlite \
-e MEMMY_MEMORY_TOKEN=release-smoke-token \
-p 127.0.0.1:28960:18960 \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=128m \
--tmpfs /data:rw,noexec,nosuid,size=128m,uid=1000,gid=1000 \
--cap-drop ALL \
--security-opt no-new-privileges:true \
memmy-memory:smoke
trap 'docker logs memmy-memory-smoke; docker rm -f memmy-memory-smoke' EXIT
node scripts/smoke-memory-docker.mjs

publish:
needs: smoke
runs-on: ubuntu-latest
steps:
- name: Check out source
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}

- name: Resolve image name
id: image
shell: bash
run: echo "name=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/memmy-memory" >> "$GITHUB_OUTPUT"

- name: Validate release tag
shell: bash
env:
IMAGE_TAG: ${{ github.event_name == 'push' && github.ref_name || inputs.tag }}
run: |
version="$(node -p "require('./package.json').version")"
if [[ "$IMAGE_TAG" == v* ]]; then
test "$IMAGE_TAG" = "v$version"
fi

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Generate image metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.image.outputs.name }}
tags: |
type=ref,event=tag
type=raw,value=${{ inputs.tag }},enable=${{ github.event_name != 'push' }}
type=sha,prefix=sha-

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: Memory/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: mode=max
sbom: true
18 changes: 16 additions & 2 deletions .github/workflows/github-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,25 @@ on:
required: true
type: string

permissions:
contents: write
permissions: {}

concurrency:
group: release-${{ github.event_name == 'workflow_dispatch' && format('release/v{0}', inputs.version) || github.event.pull_request.head.ref }}
cancel-in-progress: false

jobs:
release:
permissions:
contents: write
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
startsWith(github.event.pull_request.head.ref, 'release/v'))
runs-on: ubuntu-latest
environment: release
outputs:
tag: ${{ steps.release.outputs.tag }}
target_sha: ${{ steps.release.outputs.target_sha }}
env:
GH_TOKEN: ${{ github.token }}
steps:
Expand Down Expand Up @@ -201,3 +205,13 @@ jobs:
run: |
set -euo pipefail
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false --latest

docker:
needs: release
permissions:
contents: read
packages: write
uses: ./.github/workflows/docker-publish.yml
with:
tag: ${{ needs.release.outputs.tag }}
ref: ${{ needs.release.outputs.target_sha }}
58 changes: 58 additions & 0 deletions .github/workflows/windows-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Windows Package

on:
workflow_dispatch: {}
push:
branches:
- actions/windows-package/**

permissions:
contents: read

concurrency:
group: windows-package-${{ github.ref }}
cancel-in-progress: true

jobs:
package:
runs-on: windows-latest
timeout-minutes: 120
defaults:
run:
shell: bash
steps:
- name: Check out source
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24.15.0
cache: npm
cache-dependency-path: |
package-lock.json
App/memmy-agent/package-lock.json

- name: Prepare packaging environment
run: cp .env.example .env

- name: Build unsigned Windows x64 China installer
run: npm run package:win:x64:cn:unsigned

- name: Create SHA-256 checksum
run: |
installer="$(find App/shell/desktop/release -maxdepth 1 -type f -name 'Memmy-*-win32-x64-cn-unsigned.exe' -print -quit)"
test -n "$installer"
sha256sum "$installer" > "$installer.sha256"
ls -lh "$installer" "$installer.sha256"

- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: memmy-windows-x64-cn-unsigned-${{ github.sha }}
path: |
App/shell/desktop/release/Memmy-*-win32-x64-cn-unsigned.exe
App/shell/desktop/release/Memmy-*-win32-x64-cn-unsigned.exe.sha256
if-no-files-found: error
compression-level: 0
retention-days: 7
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ memmy-memory-*.tgz
.DS_Store
App/memmy-agent/package-lock.json
sessions/
output/
.*
!.github/
!.github/workflows/
!.github/workflows/*.yml
!.github/release-notes/
!.github/release-notes/*.md
!.dockerignore
.env
.env.*
!.env.example
3 changes: 2 additions & 1 deletion App/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ npm run db:migrate
- `adapters/inbound/local-api`: Fastify routes, runtime-token authentication,
CORS, SSE, and the Composio MCP bridge.
- `adapters/outbound/agent-source`: built-in history readers for Cursor, Claude
Code, Codex, OpenCode, OpenClaw, Hermes, and WorkBuddy.
Code, Codex, Pi, OpenCode, OpenClaw, Hermes, and WorkBuddy.
- `adapters/outbound/skill-writer`: Memory skill, hook, command, and plugin
installation for the supported agents.
- `adapters/outbound/agent-adapter`: manifest, loader, and registry contracts
Expand Down Expand Up @@ -114,6 +114,7 @@ Every route in this table requires the local runtime token.
| Cursor | Windows: `%APPDATA%\Cursor\User`; macOS: `~/Library/Application Support/Cursor/User`; Linux: `${XDG_CONFIG_HOME:-~/.config}/Cursor/User` (`workspaceStorage/*/state.vscdb` and `globalStorage/state.vscdb`) | `~/.cursor/skills/memmy-memory/` and `~/.cursor/hooks.json` |
| Claude Code | `~/.claude/projects/**/*.jsonl` | `~/.claude/CLAUDE.md`, `skills/memmy-memory/`, hooks, and the resume command |
| Codex | `~/.codex/sessions/**/rollout-*.jsonl` | `~/.codex/AGENTS.md`, `skills/memmy-memory/`, and hooks |
| Pi | `${PI_CODING_AGENT_SESSION_DIR:-~/.pi/agent/sessions}/**/*.jsonl` | `~/.pi/agent/AGENTS.md`, `skills/memmy-memory/`, and native extension |
| OpenCode | `${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` | `${XDG_CONFIG_HOME:-~/.config}/opencode/AGENTS.md`, `skills/memmy-memory/`, plugin, and resume command |
| OpenClaw | SQLite databases under `~/.openclaw/` | Workspace `AGENTS.md`, `~/.openclaw/skills/memmy-memory/`, and the Memory extension |
| Hermes | `~/.hermes/sessions/**/*.jsonl` and `~/.hermes/state.db` | `~/.hermes/SOUL.md`, `skills/memmy-memory/`, and Memory/resume plugins |
Expand Down
40 changes: 39 additions & 1 deletion App/backend/local-api-contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,52 @@ export const ByokTokenUsageSummarySchema = z.object({
});
export type ByokTokenUsageSummary = z.infer<typeof ByokTokenUsageSummarySchema>;

// --- Agent Token Usage Stats (Pi / Codex / Claude Code) ---

export const AgentKindSchema = z.enum(["pi", "codex", "claude_code"]);
export type AgentKind = z.infer<typeof AgentKindSchema>;

export const AgentTokenStatsDtoSchema = z.object({
agent: AgentKindSchema,
sessions: z.number().int().nonnegative(),
apiCalls: z.number().int().nonnegative(),
inputTokens: z.number().int().nonnegative(),
outputTokens: z.number().int().nonnegative(),
cacheReadTokens: z.number().int().nonnegative(),
cacheWriteTokens: z.number().int().nonnegative(),
reasoningTokens: z.number().int().nonnegative().optional(),
totalTokens: z.number().int().nonnegative(),
cost: z.number().nonnegative().optional(),
available: z.boolean()
});
export type AgentTokenStatsDto = z.infer<typeof AgentTokenStatsDtoSchema>;

export const ProjectTokenStatsDtoSchema = z.object({
project: z.string(),
agents: z.array(AgentTokenStatsDtoSchema),
combinedInputTokens: z.number().int().nonnegative(),
combinedOutputTokens: z.number().int().nonnegative(),
combinedCacheReadTokens: z.number().int().nonnegative(),
combinedTotalTokens: z.number().int().nonnegative(),
estimatedCost: z.number().nonnegative().optional()
});
export type ProjectTokenStatsDto = z.infer<typeof ProjectTokenStatsDtoSchema>;

export const AgentTokenStatsResponseSchema = z.object({
projects: z.array(ProjectTokenStatsDtoSchema),
scannedAt: z.string().datetime()
});
export type AgentTokenStatsResponse = z.infer<typeof AgentTokenStatsResponseSchema>;

export const AgentGatewayRuntimeConfigSchema = z.object({
baseUrl: z.string().url(),
bootstrapSecret: z.string().min(1).optional()
});
export type AgentGatewayRuntimeConfig = z.infer<typeof AgentGatewayRuntimeConfigSchema>;

export const MemoryServiceRuntimeConfigSchema = z.object({
baseUrl: z.string().url()
baseUrl: z.string().url(),
ownership: z.enum(["managed", "remote"]).default("managed")
});
export type MemoryServiceRuntimeConfig = z.infer<typeof MemoryServiceRuntimeConfigSchema>;

Expand Down
Loading