hippocamp 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +25 -0
- package/.github/workflows/publish.yml +27 -0
- package/AGENTS.md +13 -5
- package/Dockerfile.railway +15 -0
- package/README.md +64 -9
- package/assets/github-actions/hippocamp-dream.yml +34 -1
- package/assets/railway/run-dream.sh +184 -0
- package/package.json +10 -3
- package/railway.json +12 -0
- package/scripts/eval-retrieval.cjs +276 -0
- package/scripts/hippocamp-dream.cjs +185 -43
- package/scripts/hippocamp-mcp.cjs +35 -14
- package/scripts/hippocamp-memory.cjs +408 -147
- package/scripts/hippocamp.cjs +6 -0
- package/scripts/install-claude.cjs +7 -3
- package/scripts/install-codex.cjs +7 -2
- package/scripts/install-grok.cjs +260 -0
- package/skills/hippocamp-memory/SKILL.md +16 -9
- package/test/mcp-params.test.cjs +80 -0
- package/test/memory-efficiency.test.cjs +223 -0
- package/test/package-paths.test.cjs +30 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
pull_request:
|
|
6
|
+
push:
|
|
7
|
+
branches:
|
|
8
|
+
- main
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
verify:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
- uses: actions/setup-node@v6
|
|
19
|
+
with:
|
|
20
|
+
node-version: "24"
|
|
21
|
+
package-manager-cache: false
|
|
22
|
+
- run: npm ci
|
|
23
|
+
- run: node --check scripts/*.cjs
|
|
24
|
+
- run: npm run mcp:help
|
|
25
|
+
- run: npm run mcp:smoke
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Publish Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- published
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- uses: actions/setup-node@v6
|
|
18
|
+
with:
|
|
19
|
+
node-version: "24"
|
|
20
|
+
registry-url: "https://registry.npmjs.org"
|
|
21
|
+
package-manager-cache: false
|
|
22
|
+
- run: npm ci
|
|
23
|
+
- run: node --check scripts/*.cjs
|
|
24
|
+
- run: npm run mcp:smoke
|
|
25
|
+
- name: Verify release tag matches package version
|
|
26
|
+
run: test "$GITHUB_REF_NAME" = "v$(node -p "require('./package.json').version")"
|
|
27
|
+
- run: npm publish
|
package/AGENTS.md
CHANGED
|
@@ -22,14 +22,18 @@ This repository is a local-first MCP package for Git-backed agent memory. Keep c
|
|
|
22
22
|
|
|
23
23
|
## Repository Map
|
|
24
24
|
|
|
25
|
-
- `scripts/hippocamp.cjs`: small CLI wrapper for `dream`, `mcp`, `install-codex`, and `install-
|
|
25
|
+
- `scripts/hippocamp.cjs`: small CLI wrapper for `dream`, `mcp`, `install-codex`, `install-claude`, and `install-grok`.
|
|
26
26
|
- `scripts/hippocamp-dream.cjs`: offline Dream CLI for scheduled compaction of curated project wake-up files.
|
|
27
27
|
- `scripts/hippocamp-memory.cjs`: local filesystem-backed Hippocamp memory helpers for MCP use.
|
|
28
28
|
- `scripts/hippocamp-mcp.cjs`: local stdio MCP server for Hippocamp memory tools.
|
|
29
|
+
- `scripts/eval-retrieval.cjs`: retrieval-only LongMemEval-S check for `searchMemory` against a BM25 reference.
|
|
29
30
|
- `scripts/install-claude.cjs`: one-step installer for Claude Code MCP setup and user-level `CLAUDE.md` guidance.
|
|
30
31
|
- `scripts/install-codex.cjs`: one-step installer for the Hippocamp skill and MCP server in Codex.
|
|
32
|
+
- `scripts/install-grok.cjs`: one-step installer for the Hippocamp skill, Grok home rules, and MCP server in Grok Build.
|
|
31
33
|
- `skills/hippocamp-memory/SKILL.md`: installable skill that tells agents how to use Hippocamp memory.
|
|
32
34
|
- `assets/github-actions/hippocamp-dream.yml`: scheduled workflow template for Lagoon repos that opens one Dream PR per project.
|
|
35
|
+
- `assets/railway/run-dream.sh`: short-lived hosted Dream runner that clones Lagoon and opens one Dream PR per project.
|
|
36
|
+
- `Dockerfile.railway` and `railway.json`: optional Railway cron deployment for overnight Dream runs.
|
|
33
37
|
- `assets/brand/hippocamp-mascot.png`: README mascot asset.
|
|
34
38
|
|
|
35
39
|
## Project Invariants
|
|
@@ -41,12 +45,15 @@ This repository is a local-first MCP package for Git-backed agent memory. Keep c
|
|
|
41
45
|
- The current project slug is inferred from `HIPPOCAMP_PROJECT_ROOT` or the current working directory.
|
|
42
46
|
- Event logs are append-only daily Markdown files under `events/YYYY-MM-DD.md`, with sibling `events/YYYY-MM-DD.index.json` cue indexes.
|
|
43
47
|
- Curated files such as `current_state.md` and `open_threads.md` use explicit file writes.
|
|
44
|
-
-
|
|
48
|
+
- MCP `append_event` requires a title and 1-8 cues; MCP `write_memory_file` rejects paths under `events/`; an explicit `projectRoot` must be a directory inside a Git repository.
|
|
49
|
+
- `append_event` auto-stamps `Agent:` / `Session:` provenance when resolvable (installer env, MCP client name, or process session id). No manual user config.
|
|
45
50
|
- Default sync is automatic through the local Lagoon repo.
|
|
46
51
|
- Local MCP mode must not require `GITHUB_TOKEN`, GitHub App auth, or a cloud service.
|
|
47
52
|
- Memory must not duplicate facts already tracked by GitHub commits, PRs, issues, reviews, or CI. Store references plus the missing rationale, preference, assumption, or follow-up context instead.
|
|
48
53
|
- Dream compaction sends `current_state.md`, `open_threads.md`, and bounded cue-indexed event evidence for open-thread decisions. It must not dump full event logs, cue indexes, or raw GitHub-owned facts into the model prompt.
|
|
49
|
-
-
|
|
54
|
+
- Dream must compact coherent Markdown snapshots and fail without writing when the snapshot cannot fit. It must not crop wake-up files.
|
|
55
|
+
- The Dream GitHub Actions workflow is a Lagoon repo template. It should remain schedule-only and create PRs rather than pushing directly to `main`. Auto-merge is allowed only for repositories named `lagoon` after exact changed-file validation.
|
|
56
|
+
- The Railway Dream deployment is optional infrastructure. It must exit after each run, keep credentials in environment variables, and preserve the same PR policy.
|
|
50
57
|
|
|
51
58
|
## Change Rules
|
|
52
59
|
|
|
@@ -61,14 +68,15 @@ This repository is a local-first MCP package for Git-backed agent memory. Keep c
|
|
|
61
68
|
When changing code, use the smallest verification that proves the change:
|
|
62
69
|
|
|
63
70
|
- Run `node --check scripts/*.cjs` for script syntax changes.
|
|
71
|
+
- Run `npm test` for Dream compaction or memory search changes.
|
|
64
72
|
- Run `npm run mcp:help` when changing MCP registration or commands.
|
|
65
73
|
- Run `npm run mcp:smoke` when changing memory reads, root resolution, or wake-up behavior.
|
|
66
74
|
- Run `npm run dream -- --help` when changing Dream CLI arguments.
|
|
67
|
-
-
|
|
75
|
+
- Run `npm run eval:retrieval -- --limit 100` when changing search ranking or snippets; report Recall@5 against the BM25 row.
|
|
68
76
|
|
|
69
77
|
## Notes For Future Agents
|
|
70
78
|
|
|
71
79
|
- The cloud/API version is intentionally deferred.
|
|
72
80
|
- Do not reintroduce Next.js, GitHub API token auth, or GitHub App auth for the local MVP.
|
|
73
|
-
- Keep Dream minimal: scheduled
|
|
81
|
+
- Keep Dream minimal: scheduled coherent compaction, current/open curated files plus bounded thread evidence, one PR per project.
|
|
74
82
|
- The local install story should stay: install MCP, point at Lagoon, rely on normal Git auth.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FROM node:22-bookworm-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update \
|
|
4
|
+
&& apt-get install -y --no-install-recommends ca-certificates gh git \
|
|
5
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
|
|
9
|
+
COPY package.json package-lock.json ./
|
|
10
|
+
RUN npm ci --omit=dev
|
|
11
|
+
|
|
12
|
+
COPY scripts ./scripts
|
|
13
|
+
COPY assets/railway/run-dream.sh ./assets/railway/run-dream.sh
|
|
14
|
+
|
|
15
|
+
CMD ["bash", "assets/railway/run-dream.sh"]
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Hippocamp
|
|
2
2
|
|
|
3
|
+
[](https://github.com/guillaumegay13/hippocamp/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
<p align="center">
|
|
4
6
|
<img src="./assets/brand/hippocamp-mascot.png" alt="Hippocamp mascot" width="220" />
|
|
5
7
|
</p>
|
|
@@ -45,6 +47,13 @@ npm install
|
|
|
45
47
|
npm run install:claude
|
|
46
48
|
```
|
|
47
49
|
|
|
50
|
+
For Grok Build:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
npm run install:grok
|
|
55
|
+
```
|
|
56
|
+
|
|
48
57
|
After publishing, the intended one-line install shape is:
|
|
49
58
|
|
|
50
59
|
```bash
|
|
@@ -56,6 +65,7 @@ Upgrade uses the same install path, so agents can refresh themselves without a s
|
|
|
56
65
|
```bash
|
|
57
66
|
npx hippocamp@latest upgrade-codex
|
|
58
67
|
npx hippocamp@latest upgrade-claude
|
|
68
|
+
npx hippocamp@latest upgrade-grok
|
|
59
69
|
```
|
|
60
70
|
|
|
61
71
|
From a source checkout:
|
|
@@ -65,17 +75,19 @@ git pull --ff-only
|
|
|
65
75
|
npm install
|
|
66
76
|
npm run upgrade:codex
|
|
67
77
|
npm run upgrade:claude
|
|
78
|
+
npm run upgrade:grok
|
|
68
79
|
```
|
|
69
80
|
|
|
70
|
-
|
|
81
|
+
Installers default to `~/.lagoon` as the memory repo. You can override it:
|
|
71
82
|
|
|
72
83
|
```bash
|
|
73
84
|
npm run install:codex -- --global-root /absolute/path/to/lagoon
|
|
74
85
|
npm run install:claude -- --global-root /absolute/path/to/lagoon
|
|
86
|
+
npm run install:grok -- --global-root /absolute/path/to/lagoon
|
|
75
87
|
```
|
|
76
88
|
|
|
77
|
-
The Codex installer refreshes `~/.codex/AGENTS.md`. The Claude installer refreshes `~/.claude/CLAUDE.md`.
|
|
78
|
-
|
|
89
|
+
The Codex installer refreshes `~/.codex/AGENTS.md`. The Claude installer refreshes `~/.claude/CLAUDE.md`. The Grok installer refreshes `~/.grok/rules/hippocamp.md` and registers the MCP server with `HIPPOCAMP_AGENT=grok`.
|
|
90
|
+
Managed instruction blocks tell the agent to call `wake_up` at the start of new top-level coding tasks before repo exploration or edits.
|
|
79
91
|
|
|
80
92
|
## Lagoon Repo
|
|
81
93
|
|
|
@@ -145,13 +157,13 @@ Typical agent flow:
|
|
|
145
157
|
|
|
146
158
|
1. Call `wake_up` at the start of a top-level task.
|
|
147
159
|
2. Read the returned global and project memory.
|
|
148
|
-
3. Use `search_memory`
|
|
149
|
-
4. Use `append_event` for meaningful milestones, with concise cues
|
|
160
|
+
3. Use `search_memory` for task-specific recall after wake-up.
|
|
161
|
+
4. Use `append_event` for meaningful milestones, with a title and 1-8 concise cues.
|
|
150
162
|
5. Update curated files like `current_state.md` and `open_threads.md` before finishing.
|
|
151
163
|
|
|
152
164
|
Writes sync by default. If sync fails or is skipped, call `sync_memory`.
|
|
153
165
|
|
|
154
|
-
Event writes update a sibling `events/YYYY-MM-DD.index.json` file. The Markdown event remains the canonical memory; the sidecar
|
|
166
|
+
Event writes update a sibling `events/YYYY-MM-DD.index.json` file. The Markdown event remains the canonical memory; the sidecar is rebuildable. Search ranks indexed events and curated files with BM25 and typo tolerance ([MiniSearch](https://github.com/lucaong/minisearch)), weighting cues above titles and titles above bodies. It returns small coherent evidence blocks from indexed events. If no indexed result is strong enough, it returns no event result instead of scanning whole event logs.
|
|
155
167
|
|
|
156
168
|
## Dream
|
|
157
169
|
|
|
@@ -162,7 +174,9 @@ projects/<project-slug>/current_state.md
|
|
|
162
174
|
projects/<project-slug>/open_threads.md
|
|
163
175
|
```
|
|
164
176
|
|
|
165
|
-
It does not dump event logs into the model prompt, does not rewrite append-only events, and does not run during normal MCP wake-up. When a project is over the threshold, Dream builds a capped thread evidence pack by searching cue-indexed project events for `open_threads.md` bullets. The evidence budget follows `--target-chars`, so the same size target controls both the desired output and the supporting context.
|
|
177
|
+
It does not dump event logs into the model prompt, does not rewrite append-only events, and does not run during normal MCP wake-up. When a project is over the threshold, Dream builds a capped thread evidence pack by searching cue-indexed project events for `open_threads.md` bullets. The evidence budget follows `--target-chars`, so the same size target controls both the desired output and the supporting context.
|
|
178
|
+
|
|
179
|
+
Dream uses an Eve-style compaction loop. It rewrites the complete curated snapshot, measures the result, and compacts that coherent result again when it is still over the target. It never crops a wake-up file. After three passes, it fails without writing either file if the snapshot still does not fit.
|
|
166
180
|
|
|
167
181
|
Dry-run is the default:
|
|
168
182
|
|
|
@@ -177,21 +191,43 @@ npm run dream -- --project my-project --write
|
|
|
177
191
|
- `MANIFEST_API_KEY`
|
|
178
192
|
- `HIPPOCAMP_DREAM_MODEL` (defaults to `auto`; override if you want a specific provider/model)
|
|
179
193
|
|
|
180
|
-
The GitHub Actions template at `assets/github-actions/hippocamp-dream.yml` is meant to be copied into the private Lagoon memory repo as `.github/workflows/hippocamp-dream.yml`. It runs on a schedule only, scans projects over the wake-up threshold, and creates or updates one PR per project
|
|
194
|
+
The GitHub Actions template at `assets/github-actions/hippocamp-dream.yml` is meant to be copied into the private Lagoon memory repo as `.github/workflows/hippocamp-dream.yml`. It runs on a schedule only, scans projects over the wake-up threshold, and creates or updates one PR per project. With `HIPPOCAMP_DREAM_AUTO_MERGE=true`, Dream squash-merges the PR only when the repository name is `lagoon` and the PR changes only the two curated project files.
|
|
195
|
+
|
|
196
|
+
### Railway
|
|
197
|
+
|
|
198
|
+
Railway can run Dream overnight even when your computer is offline. The included cron service starts once per day at `03:17 UTC`, clones the private Lagoon repo, creates or updates one Dream PR per candidate project, and exits. Set `HIPPOCAMP_DREAM_AUTO_MERGE=true` to enable the same Lagoon-only auto-merge policy.
|
|
199
|
+
|
|
200
|
+
[](https://railway.com/deploy/hippocamp)
|
|
201
|
+
|
|
202
|
+
Required template variables:
|
|
203
|
+
|
|
204
|
+
- `LAGOON_REPOSITORY`: private memory repo in `owner/repository` form
|
|
205
|
+
- `GITHUB_TOKEN`: fine-grained GitHub token limited to that repo, with read/write access to Contents and Pull requests
|
|
206
|
+
- `MANIFEST_BASE_URL`: Manifest/OpenAI-compatible base URL
|
|
207
|
+
- `MANIFEST_API_KEY`: API key for Dream model requests
|
|
208
|
+
|
|
209
|
+
Optional variables keep the CLI defaults: `HIPPOCAMP_DREAM_MODEL=auto`, `HIPPOCAMP_DREAM_THRESHOLD_CHARS=20000`, and `HIPPOCAMP_DREAM_TARGET_CHARS=15000`. `HIPPOCAMP_DREAM_AUTO_MERGE=true` enables a guarded squash merge for a repository named `lagoon`.
|
|
210
|
+
|
|
211
|
+
Railway is an optional deployment target. Local MCP reads and writes do not use Railway or require these hosted credentials.
|
|
181
212
|
|
|
182
213
|
## Memory Rules
|
|
183
214
|
|
|
184
215
|
- Keep memory concise.
|
|
185
216
|
- Prefer curated summaries over raw event history.
|
|
186
|
-
- Give events a short `Cues:` section
|
|
217
|
+
- Give events a short `Cues:` section; cues weigh the most in search ranking.
|
|
187
218
|
- Do not duplicate GitHub-owned facts such as commits, PRs, issues, reviews, or CI results.
|
|
188
219
|
- Store artifact references plus the missing rationale, preference, assumption, or follow-up context.
|
|
189
220
|
- Use project scope for project-specific state.
|
|
190
221
|
- Use global scope only for durable context that should follow you across projects.
|
|
191
222
|
|
|
223
|
+
Events are stamped automatically with agent/session provenance when available (`Agent:` / `Session:` lines). Installers set `HIPPOCAMP_AGENT`; session defaults to a process-lifetime id. No manual config is required.
|
|
224
|
+
|
|
192
225
|
Example event content:
|
|
193
226
|
|
|
194
227
|
```md
|
|
228
|
+
Agent: claude
|
|
229
|
+
Session: mcp-a1b2c3d4
|
|
230
|
+
|
|
195
231
|
Cues:
|
|
196
232
|
- local-first
|
|
197
233
|
- token-free
|
|
@@ -215,12 +251,30 @@ npm run mcp
|
|
|
215
251
|
npm run mcp:help
|
|
216
252
|
npm run mcp:smoke
|
|
217
253
|
npm run dream
|
|
254
|
+
npm run dream:railway
|
|
255
|
+
npm run eval:retrieval
|
|
218
256
|
npm run install:codex
|
|
219
257
|
npm run install:claude
|
|
258
|
+
npm run install:grok
|
|
220
259
|
npm run upgrade:codex
|
|
221
260
|
npm run upgrade:claude
|
|
261
|
+
npm run upgrade:grok
|
|
222
262
|
```
|
|
223
263
|
|
|
264
|
+
`npm run eval:retrieval` measures search on LongMemEval-S without any model: Recall@5, Hit@5, MRR, returned context size, and latency, next to an in-process BM25 reference. Run it with `--help` for the one-time data download.
|
|
265
|
+
|
|
266
|
+
## Releases
|
|
267
|
+
|
|
268
|
+
Pull requests and pushes to `main` run syntax and MCP smoke checks in GitHub Actions.
|
|
269
|
+
|
|
270
|
+
To publish a package version:
|
|
271
|
+
|
|
272
|
+
1. Update the version in `package.json` and `package-lock.json`, then merge it to `main`.
|
|
273
|
+
2. Publish a GitHub Release whose tag is `v<version>`.
|
|
274
|
+
3. The `Publish Package` workflow verifies the tag, runs the MCP checks, and publishes to npm through trusted publishing.
|
|
275
|
+
|
|
276
|
+
The npm package must trust the GitHub Actions workflow `publish.yml` in `guillaumegay13/hippocamp`. This uses short-lived OIDC credentials instead of an npm token.
|
|
277
|
+
|
|
224
278
|
## Configuration
|
|
225
279
|
|
|
226
280
|
Environment variables are optional for local use:
|
|
@@ -233,6 +287,7 @@ Environment variables are optional for local use:
|
|
|
233
287
|
- `HIPPOCAMP_DREAM_MODEL`: model used by Dream. Default: `auto`
|
|
234
288
|
- `HIPPOCAMP_DREAM_THRESHOLD_CHARS`: wake-up size required before Dream proposes compaction. Default: `20000`
|
|
235
289
|
- `HIPPOCAMP_DREAM_TARGET_CHARS`: target combined size for `current_state.md` and `open_threads.md`. Default: `15000`
|
|
290
|
+
- `HIPPOCAMP_DREAM_AUTO_MERGE`: set to `true` for a guarded squash merge in a repository named `lagoon`
|
|
236
291
|
|
|
237
292
|
## What This Is Not
|
|
238
293
|
|
|
@@ -22,7 +22,9 @@ jobs:
|
|
|
22
22
|
HIPPOCAMP_GLOBAL_ROOT: ${{ github.workspace }}
|
|
23
23
|
HIPPOCAMP_DREAM_THRESHOLD_CHARS: "20000"
|
|
24
24
|
HIPPOCAMP_DREAM_TARGET_CHARS: "15000"
|
|
25
|
+
HIPPOCAMP_DREAM_AUTO_MERGE: "true"
|
|
25
26
|
HIPPOCAMP_DREAM_MODEL: ${{ secrets.HIPPOCAMP_DREAM_MODEL }}
|
|
27
|
+
LAGOON_REPOSITORY: ${{ github.repository }}
|
|
26
28
|
MANIFEST_BASE_URL: ${{ secrets.MANIFEST_BASE_URL }}
|
|
27
29
|
MANIFEST_API_KEY: ${{ secrets.MANIFEST_API_KEY }}
|
|
28
30
|
|
|
@@ -65,6 +67,31 @@ jobs:
|
|
|
65
67
|
run: |
|
|
66
68
|
set -euo pipefail
|
|
67
69
|
|
|
70
|
+
enable_lagoon_auto_merge() {
|
|
71
|
+
local project="$1"
|
|
72
|
+
local pr_number="$2"
|
|
73
|
+
|
|
74
|
+
[ "$HIPPOCAMP_DREAM_AUTO_MERGE" = "true" ] || return 0
|
|
75
|
+
|
|
76
|
+
if [ "${LAGOON_REPOSITORY##*/}" != "lagoon" ]; then
|
|
77
|
+
echo "Skipping auto-merge: ${LAGOON_REPOSITORY} is not a repository named lagoon." >&2
|
|
78
|
+
return 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
local changed_path
|
|
82
|
+
while IFS= read -r changed_path; do
|
|
83
|
+
case "$changed_path" in
|
|
84
|
+
"projects/${project}/current_state.md"|"projects/${project}/open_threads.md") ;;
|
|
85
|
+
*)
|
|
86
|
+
echo "Refusing auto-merge: unexpected changed path ${changed_path}." >&2
|
|
87
|
+
return 1
|
|
88
|
+
;;
|
|
89
|
+
esac
|
|
90
|
+
done < <(git diff --name-only origin/main...HEAD)
|
|
91
|
+
|
|
92
|
+
gh pr merge "$pr_number" --squash --delete-branch
|
|
93
|
+
}
|
|
94
|
+
|
|
68
95
|
while IFS= read -r project; do
|
|
69
96
|
[ -n "$project" ] || continue
|
|
70
97
|
|
|
@@ -113,6 +140,7 @@ jobs:
|
|
|
113
140
|
"After:",
|
|
114
141
|
`- wake_up: ${result.afterWakeUpChars} chars`,
|
|
115
142
|
`- current_state.md + open_threads.md: ${result.afterBytes} bytes`,
|
|
143
|
+
`- coherent compaction passes: ${result.compactionPasses}`,
|
|
116
144
|
"",
|
|
117
145
|
"Policy:",
|
|
118
146
|
"- touched only `current_state.md` and `open_threads.md`",
|
|
@@ -128,10 +156,15 @@ jobs:
|
|
|
128
156
|
|
|
129
157
|
if [ -n "$existing" ]; then
|
|
130
158
|
gh pr edit "$existing" --title "$title" --body-file "/tmp/hippocamp-dream-${project}.md"
|
|
159
|
+
pr_number="$existing"
|
|
131
160
|
else
|
|
132
|
-
gh pr create --title "$title" --body-file "/tmp/hippocamp-dream-${project}.md" --head "$branch" --base main
|
|
161
|
+
gh pr create --title "$title" --body-file "/tmp/hippocamp-dream-${project}.md" --head "$branch" --base main >/dev/null
|
|
162
|
+
pr_number="$(gh pr list --head "$branch" --state open --json number --jq '.[0].number // empty')"
|
|
133
163
|
fi
|
|
134
164
|
|
|
165
|
+
[ -n "$pr_number" ] || { echo "Could not resolve Dream PR number for ${project}." >&2; exit 1; }
|
|
166
|
+
enable_lagoon_auto_merge "$project" "$pr_number"
|
|
167
|
+
|
|
135
168
|
git checkout main
|
|
136
169
|
git reset --hard origin/main
|
|
137
170
|
done < /tmp/hippocamp-dream-projects.txt
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
required=(
|
|
6
|
+
GITHUB_TOKEN
|
|
7
|
+
LAGOON_REPOSITORY
|
|
8
|
+
MANIFEST_API_KEY
|
|
9
|
+
MANIFEST_BASE_URL
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
for name in "${required[@]}"; do
|
|
13
|
+
if [[ -z "${!name:-}" ]]; then
|
|
14
|
+
echo "Missing required environment variable: ${name}" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
done
|
|
18
|
+
|
|
19
|
+
if [[ ! "$LAGOON_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
|
|
20
|
+
echo "LAGOON_REPOSITORY must use the owner/repository form." >&2
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
export GH_TOKEN="$GITHUB_TOKEN"
|
|
25
|
+
export HIPPOCAMP_DREAM_MODEL="${HIPPOCAMP_DREAM_MODEL:-auto}"
|
|
26
|
+
export HIPPOCAMP_DREAM_TARGET_CHARS="${HIPPOCAMP_DREAM_TARGET_CHARS:-15000}"
|
|
27
|
+
export HIPPOCAMP_DREAM_THRESHOLD_CHARS="${HIPPOCAMP_DREAM_THRESHOLD_CHARS:-20000}"
|
|
28
|
+
export HIPPOCAMP_DREAM_AUTO_MERGE="${HIPPOCAMP_DREAM_AUTO_MERGE:-false}"
|
|
29
|
+
|
|
30
|
+
runner_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
31
|
+
work_root="$(mktemp -d)"
|
|
32
|
+
lagoon_root="$work_root/lagoon"
|
|
33
|
+
|
|
34
|
+
cleanup() {
|
|
35
|
+
rm -rf "$work_root"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
trap cleanup EXIT
|
|
39
|
+
|
|
40
|
+
gh auth setup-git
|
|
41
|
+
gh repo clone "$LAGOON_REPOSITORY" "$lagoon_root"
|
|
42
|
+
|
|
43
|
+
cd "$lagoon_root"
|
|
44
|
+
git config user.name "${HIPPOCAMP_DREAM_GIT_NAME:-hippocamp-dream[bot]}"
|
|
45
|
+
git config user.email "${HIPPOCAMP_DREAM_GIT_EMAIL:-hippocamp-dream[bot]@users.noreply.github.com}"
|
|
46
|
+
|
|
47
|
+
export HIPPOCAMP_GLOBAL_ROOT="$lagoon_root"
|
|
48
|
+
|
|
49
|
+
node "$runner_root/scripts/hippocamp-dream.cjs" \
|
|
50
|
+
--all \
|
|
51
|
+
--dry-run \
|
|
52
|
+
--json \
|
|
53
|
+
--threshold-chars "$HIPPOCAMP_DREAM_THRESHOLD_CHARS" \
|
|
54
|
+
> "$work_root/scan.json"
|
|
55
|
+
|
|
56
|
+
node - "$work_root/scan.json" > "$work_root/projects.txt" <<'NODE'
|
|
57
|
+
const fs = require("node:fs");
|
|
58
|
+
const scan = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
|
59
|
+
const projects = scan.results
|
|
60
|
+
.filter((item) => item.skipped === "dry_run")
|
|
61
|
+
.map((item) => item.project);
|
|
62
|
+
process.stdout.write(`${projects.join("\n")}${projects.length ? "\n" : ""}`);
|
|
63
|
+
console.error(`Dream candidates: ${projects.length ? projects.join(", ") : "none"}`);
|
|
64
|
+
NODE
|
|
65
|
+
|
|
66
|
+
failed=()
|
|
67
|
+
|
|
68
|
+
enable_lagoon_auto_merge() {
|
|
69
|
+
local project="$1"
|
|
70
|
+
local pr_number="$2"
|
|
71
|
+
|
|
72
|
+
[[ "$HIPPOCAMP_DREAM_AUTO_MERGE" == "true" ]] || return 0
|
|
73
|
+
|
|
74
|
+
if [[ "${LAGOON_REPOSITORY##*/}" != "lagoon" ]]; then
|
|
75
|
+
echo "Skipping auto-merge: ${LAGOON_REPOSITORY} is not a repository named lagoon." >&2
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
local changed_path
|
|
80
|
+
while IFS= read -r changed_path; do
|
|
81
|
+
case "$changed_path" in
|
|
82
|
+
"projects/${project}/current_state.md"|"projects/${project}/open_threads.md") ;;
|
|
83
|
+
*)
|
|
84
|
+
echo "Refusing auto-merge: unexpected changed path ${changed_path}." >&2
|
|
85
|
+
return 1
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
done < <(git diff --name-only origin/main...HEAD)
|
|
89
|
+
|
|
90
|
+
gh pr merge "$pr_number" --repo "$LAGOON_REPOSITORY" --squash --delete-branch
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
while IFS= read -r project; do
|
|
94
|
+
[[ -n "$project" ]] || continue
|
|
95
|
+
|
|
96
|
+
branch="dream/${project}"
|
|
97
|
+
result_file="$work_root/${project}.json"
|
|
98
|
+
body_file="$work_root/${project}.md"
|
|
99
|
+
|
|
100
|
+
git fetch origin main
|
|
101
|
+
git checkout -B "$branch" origin/main
|
|
102
|
+
|
|
103
|
+
if ! node "$runner_root/scripts/hippocamp-dream.cjs" \
|
|
104
|
+
--project "$project" \
|
|
105
|
+
--write \
|
|
106
|
+
--json \
|
|
107
|
+
--threshold-chars "$HIPPOCAMP_DREAM_THRESHOLD_CHARS" \
|
|
108
|
+
--target-chars "$HIPPOCAMP_DREAM_TARGET_CHARS" \
|
|
109
|
+
> "$result_file"; then
|
|
110
|
+
echo "Dream failed for ${project}; continuing with remaining projects." >&2
|
|
111
|
+
failed+=("$project")
|
|
112
|
+
git checkout -- .
|
|
113
|
+
continue
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if git diff --quiet -- "projects/${project}/current_state.md" "projects/${project}/open_threads.md"; then
|
|
117
|
+
echo "No Dream diff for ${project}"
|
|
118
|
+
continue
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
git add "projects/${project}/current_state.md" "projects/${project}/open_threads.md"
|
|
122
|
+
git commit -m "Dream compact ${project} memory"
|
|
123
|
+
|
|
124
|
+
if git ls-remote --exit-code --heads origin "refs/heads/${branch}" >/dev/null 2>&1; then
|
|
125
|
+
git fetch origin "refs/heads/${branch}:refs/remotes/origin/${branch}"
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
git push --force-with-lease origin "HEAD:refs/heads/${branch}"
|
|
129
|
+
|
|
130
|
+
node - "$project" "$result_file" > "$body_file" <<'NODE'
|
|
131
|
+
const fs = require("node:fs");
|
|
132
|
+
const project = process.argv[2];
|
|
133
|
+
const payload = JSON.parse(fs.readFileSync(process.argv[3], "utf8"));
|
|
134
|
+
const result = payload.results[0];
|
|
135
|
+
const lines = [
|
|
136
|
+
`Dream compacted \`${project}\` curated memory.`,
|
|
137
|
+
"",
|
|
138
|
+
"Before:",
|
|
139
|
+
`- wake_up: ${result.wakeUpChars} chars`,
|
|
140
|
+
`- current_state.md: ${result.files["current_state.md"]} bytes`,
|
|
141
|
+
`- open_threads.md: ${result.files["open_threads.md"]} bytes`,
|
|
142
|
+
"",
|
|
143
|
+
"Context:",
|
|
144
|
+
`- open threads found: ${result.context.openThreads}`,
|
|
145
|
+
`- threads with event evidence: ${result.context.threadsWithEvidence}`,
|
|
146
|
+
`- event evidence snippets: ${result.context.evidenceItems}`,
|
|
147
|
+
`- evidence budget used: ${result.context.evidenceChars}/${result.context.evidenceBudgetChars} chars`,
|
|
148
|
+
"",
|
|
149
|
+
"After:",
|
|
150
|
+
`- wake_up: ${result.afterWakeUpChars} chars`,
|
|
151
|
+
`- current_state.md + open_threads.md: ${result.afterBytes} bytes`,
|
|
152
|
+
`- coherent compaction passes: ${result.compactionPasses}`,
|
|
153
|
+
"",
|
|
154
|
+
"Policy:",
|
|
155
|
+
"- touched only `current_state.md` and `open_threads.md`",
|
|
156
|
+
"- used bounded cue-indexed event evidence for thread decisions",
|
|
157
|
+
"- did not modify append-only events or cue indexes",
|
|
158
|
+
"- moved historical detail out of wake-up context",
|
|
159
|
+
];
|
|
160
|
+
console.log(lines.join("\n"));
|
|
161
|
+
NODE
|
|
162
|
+
|
|
163
|
+
existing="$(gh pr list --repo "$LAGOON_REPOSITORY" --head "$branch" --state open --json number --jq '.[0].number // empty')"
|
|
164
|
+
title="Dream compact ${project} memory"
|
|
165
|
+
|
|
166
|
+
if [[ -n "$existing" ]]; then
|
|
167
|
+
gh api --method PATCH "repos/${LAGOON_REPOSITORY}/pulls/${existing}" \
|
|
168
|
+
--raw-field title="$title" \
|
|
169
|
+
--field "body=@${body_file}" \
|
|
170
|
+
>/dev/null
|
|
171
|
+
pr_number="$existing"
|
|
172
|
+
else
|
|
173
|
+
gh pr create --repo "$LAGOON_REPOSITORY" --title "$title" --body-file "$body_file" --head "$branch" --base main >/dev/null
|
|
174
|
+
pr_number="$(gh pr list --repo "$LAGOON_REPOSITORY" --head "$branch" --state open --json number --jq '.[0].number // empty')"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
[[ -n "$pr_number" ]] || { echo "Could not resolve Dream PR number for ${project}." >&2; exit 1; }
|
|
178
|
+
enable_lagoon_auto_merge "$project" "$pr_number"
|
|
179
|
+
done < "$work_root/projects.txt"
|
|
180
|
+
|
|
181
|
+
if ((${#failed[@]})); then
|
|
182
|
+
echo "Dream failed for: ${failed[*]}" >&2
|
|
183
|
+
echo "Exiting 0 so the cron deployment is not marked crashed; failures above are transient per-project model errors." >&2
|
|
184
|
+
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hippocamp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Local Git-backed memory for AI agents.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,20 +24,27 @@
|
|
|
24
24
|
"hippocamp-dream": "scripts/hippocamp-dream.cjs",
|
|
25
25
|
"hippocamp-mcp": "scripts/hippocamp-mcp.cjs",
|
|
26
26
|
"hippocamp-install-codex": "scripts/install-codex.cjs",
|
|
27
|
-
"hippocamp-install-claude": "scripts/install-claude.cjs"
|
|
27
|
+
"hippocamp-install-claude": "scripts/install-claude.cjs",
|
|
28
|
+
"hippocamp-install-grok": "scripts/install-grok.cjs"
|
|
28
29
|
},
|
|
29
30
|
"scripts": {
|
|
30
31
|
"dream": "node scripts/hippocamp-dream.cjs",
|
|
32
|
+
"dream:railway": "bash assets/railway/run-dream.sh",
|
|
33
|
+
"eval:retrieval": "node scripts/eval-retrieval.cjs",
|
|
31
34
|
"install:claude": "node scripts/install-claude.cjs",
|
|
32
35
|
"install:codex": "node scripts/install-codex.cjs",
|
|
36
|
+
"install:grok": "node scripts/install-grok.cjs",
|
|
33
37
|
"mcp": "node scripts/hippocamp-mcp.cjs",
|
|
34
38
|
"mcp:help": "node scripts/hippocamp-mcp.cjs --help",
|
|
35
39
|
"mcp:smoke": "node scripts/hippocamp-mcp.cjs --smoke",
|
|
40
|
+
"test": "node --test test/*.test.cjs",
|
|
36
41
|
"upgrade:claude": "node scripts/install-claude.cjs",
|
|
37
|
-
"upgrade:codex": "node scripts/install-codex.cjs"
|
|
42
|
+
"upgrade:codex": "node scripts/install-codex.cjs",
|
|
43
|
+
"upgrade:grok": "node scripts/install-grok.cjs"
|
|
38
44
|
},
|
|
39
45
|
"dependencies": {
|
|
40
46
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
47
|
+
"minisearch": "^7.2.0",
|
|
41
48
|
"zod": "^4.3.6"
|
|
42
49
|
}
|
|
43
50
|
}
|
package/railway.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://railway.com/railway.schema.json",
|
|
3
|
+
"build": {
|
|
4
|
+
"builder": "DOCKERFILE",
|
|
5
|
+
"dockerfilePath": "Dockerfile.railway"
|
|
6
|
+
},
|
|
7
|
+
"deploy": {
|
|
8
|
+
"cronSchedule": "17 3 * * *",
|
|
9
|
+
"restartPolicyType": "NEVER",
|
|
10
|
+
"startCommand": "bash assets/railway/run-dream.sh"
|
|
11
|
+
}
|
|
12
|
+
}
|