dreaming-memory 0.2.0__tar.gz

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.
Files changed (46) hide show
  1. dreaming_memory-0.2.0/.env.example +19 -0
  2. dreaming_memory-0.2.0/.gitignore +12 -0
  3. dreaming_memory-0.2.0/PKG-INFO +110 -0
  4. dreaming_memory-0.2.0/README.md +55 -0
  5. dreaming_memory-0.2.0/deploy/cloudflare/utrecht-dataos-api.worker.js +53 -0
  6. dreaming_memory-0.2.0/deploy/fleet/README.md +53 -0
  7. dreaming_memory-0.2.0/deploy/fleet/agent-memory-dashboard.service +14 -0
  8. dreaming_memory-0.2.0/deploy/fleet/agent-memory-eval.service +10 -0
  9. dreaming_memory-0.2.0/deploy/fleet/agent-memory-eval.timer +11 -0
  10. dreaming_memory-0.2.0/deploy/fleet/cloudflare_tunnel.py +114 -0
  11. dreaming_memory-0.2.0/deploy/fleet/install-agent-memory.sh +23 -0
  12. dreaming_memory-0.2.0/deploy/fleet/install-memory.sh +51 -0
  13. dreaming_memory-0.2.0/deploy/fleet/sync-env.sh +35 -0
  14. dreaming_memory-0.2.0/deploy/oci/README.md +98 -0
  15. dreaming_memory-0.2.0/deploy/oci/docker-compose.yml +21 -0
  16. dreaming_memory-0.2.0/deploy/oci/prefect_flow.py +74 -0
  17. dreaming_memory-0.2.0/examples/linear_memory_flow.py +66 -0
  18. dreaming_memory-0.2.0/pyproject.toml +96 -0
  19. dreaming_memory-0.2.0/src/dreaming_memory/__init__.py +18 -0
  20. dreaming_memory-0.2.0/src/dreaming_memory/agent_memory.py +161 -0
  21. dreaming_memory-0.2.0/src/dreaming_memory/cli.py +262 -0
  22. dreaming_memory-0.2.0/src/dreaming_memory/config.py +130 -0
  23. dreaming_memory-0.2.0/src/dreaming_memory/dashboard.py +150 -0
  24. dreaming_memory-0.2.0/src/dreaming_memory/integrations/__init__.py +13 -0
  25. dreaming_memory-0.2.0/src/dreaming_memory/integrations/cloudflare.py +62 -0
  26. dreaming_memory-0.2.0/src/dreaming_memory/integrations/linear.py +301 -0
  27. dreaming_memory-0.2.0/src/dreaming_memory/integrations/notion.py +142 -0
  28. dreaming_memory-0.2.0/src/dreaming_memory/integrations/slack.py +87 -0
  29. dreaming_memory-0.2.0/src/dreaming_memory/observability/__init__.py +4 -0
  30. dreaming_memory-0.2.0/src/dreaming_memory/observability/sentry.py +58 -0
  31. dreaming_memory-0.2.0/src/dreaming_memory/py.typed +1 -0
  32. dreaming_memory-0.2.0/src/dreaming_memory/semantic/__init__.py +3 -0
  33. dreaming_memory-0.2.0/src/dreaming_memory/semantic/lancedb.py +74 -0
  34. dreaming_memory-0.2.0/src/dreaming_memory/session.py +86 -0
  35. dreaming_memory-0.2.0/src/dreaming_memory/store/__init__.py +3 -0
  36. dreaming_memory-0.2.0/src/dreaming_memory/store/migrations/schema_v1.sql +39 -0
  37. dreaming_memory-0.2.0/src/dreaming_memory/store/migrations/schema_v2.sql +13 -0
  38. dreaming_memory-0.2.0/src/dreaming_memory/store/migrations/schema_v3.sql +47 -0
  39. dreaming_memory-0.2.0/src/dreaming_memory/store/oci.py +51 -0
  40. dreaming_memory-0.2.0/src/dreaming_memory/store/postgres.py +282 -0
  41. dreaming_memory-0.2.0/src/dreaming_memory/store/schema.sql +39 -0
  42. dreaming_memory-0.2.0/src/dreaming_memory/triage.py +175 -0
  43. dreaming_memory-0.2.0/src/dreaming_memory/types.py +64 -0
  44. dreaming_memory-0.2.0/tests/test_export.py +35 -0
  45. dreaming_memory-0.2.0/tests/test_memory.py +96 -0
  46. dreaming_memory-0.2.0/tests/test_slack.py +68 -0
@@ -0,0 +1,19 @@
1
+ # Agent memory — development defaults (copy to .env, never commit secrets)
2
+
3
+ # Postgres SSOT (required)
4
+ AGENT_MEMORY_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/agent_memory
5
+
6
+ # Linear (same keys as utrecht-data-os)
7
+ # LINEAR_API_KEY=lin_api_...
8
+ # LINEAR_TEAM_ID=
9
+ # LINEAR_TEAM_KEY=GROEP
10
+
11
+ # Notion
12
+ # NOTION_API_KEY=secret_...
13
+ # NOTION_TOKEN=secret_...
14
+
15
+ # Slack (incoming webhook for eval reports)
16
+ SLACK_WEBHOOK_URL=
17
+
18
+ # Optional LanceDB (local path or s3:// for R2)
19
+ # LANCE_DB_URI=./data/lancedb
@@ -0,0 +1,12 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .env
5
+ .env.*
6
+ !.env.example
7
+ data/lancedb/
8
+ .pytest_cache/
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+ uv.lock
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: dreaming-memory
3
+ Version: 0.2.0
4
+ Summary: Agent-agnostic memory extension — Postgres-backed agent memory with Linear, Notion, and Cloudflare integrations
5
+ Project-URL: Homepage, https://github.com/OnlineChefGroep/cursor-dreaming-sdk
6
+ Project-URL: Documentation, https://github.com/OnlineChefGroep/cursor-dreaming-sdk/tree/main/docs
7
+ Project-URL: Repository, https://github.com/OnlineChefGroep/cursor-dreaming-sdk
8
+ Project-URL: Issues, https://github.com/OnlineChefGroep/cursor-dreaming-sdk/issues
9
+ Author: OnlineChefGroep
10
+ License: MIT
11
+ Keywords: agent-memory,dream-eval,linear,notion,postgres,postgrest
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: System :: Monitoring
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: <3.15,>=3.11
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: psycopg-pool>=3.1
25
+ Requires-Dist: psycopg[binary]>=3.2
26
+ Requires-Dist: pydantic>=2.13
27
+ Provides-Extra: all
28
+ Requires-Dist: boto3>=1.35; extra == 'all'
29
+ Requires-Dist: fastapi>=0.115; extra == 'all'
30
+ Requires-Dist: lancedb>=0.22; extra == 'all'
31
+ Requires-Dist: pyarrow>=18.0; extra == 'all'
32
+ Requires-Dist: sentry-sdk>=2.19; extra == 'all'
33
+ Requires-Dist: upstash-redis>=1.2; extra == 'all'
34
+ Requires-Dist: uvicorn[standard]>=0.30; extra == 'all'
35
+ Provides-Extra: dev
36
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
37
+ Requires-Dist: pytest>=8.0; extra == 'dev'
38
+ Requires-Dist: pyyaml>=6.0; extra == 'dev'
39
+ Requires-Dist: ruff>=0.15; extra == 'dev'
40
+ Provides-Extra: prefect
41
+ Requires-Dist: prefect>=3.0; extra == 'prefect'
42
+ Provides-Extra: r2
43
+ Requires-Dist: boto3>=1.35; extra == 'r2'
44
+ Provides-Extra: redis
45
+ Requires-Dist: upstash-redis>=1.2; extra == 'redis'
46
+ Provides-Extra: semantic
47
+ Requires-Dist: lancedb>=0.22; extra == 'semantic'
48
+ Requires-Dist: pyarrow>=18.0; extra == 'semantic'
49
+ Provides-Extra: sentry
50
+ Requires-Dist: sentry-sdk>=2.19; extra == 'sentry'
51
+ Provides-Extra: web
52
+ Requires-Dist: fastapi>=0.115; extra == 'web'
53
+ Requires-Dist: uvicorn[standard]>=0.30; extra == 'web'
54
+ Description-Content-Type: text/markdown
55
+
56
+ # cursor-dreaming-memory
57
+
58
+ Lightweight agent memory extension for **cursor-dreaming-sdk** (Utrecht Data OS / CHEF-308).
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ cd python
64
+ uv sync --extra dev
65
+ uv run dream-memory init # requires Postgres
66
+ ```
67
+
68
+ Optional semantic layer:
69
+
70
+ ```bash
71
+ uv sync --extra semantic
72
+ ```
73
+
74
+ ## Quick start
75
+
76
+ ```python
77
+ from cursor_dreaming_memory import AgentMemory, SessionContext
78
+ from cursor_dreaming_memory.types import MemoryType, MemorySource
79
+
80
+ memory = AgentMemory()
81
+ memory.ensure_schema()
82
+
83
+ ctx = SessionContext.for_dream_eval("2026-06-15T09-00-00Z")
84
+ memory.remember(ctx, MemoryType.OBSERVATION, {"faithfulness": 0.63}, source=MemorySource.SDK)
85
+ ```
86
+
87
+ ## CLI
88
+
89
+ ```bash
90
+ dream-memory init
91
+ dream-memory remember --session-id run-1 --content '{"note":"hello"}'
92
+ dream-memory recall --session-id run-1
93
+ dream-memory linear-ingest CHEF-308
94
+ dream-memory notion-ingest <page_id>
95
+ dream-memory export --session-id run-1 --output run-1.md
96
+ dream-memory slack-report --run-id run-1 --metrics-json metrics.json
97
+ dream-memory doctor
98
+ ```
99
+
100
+ - `export` writes a session's memory records as Markdown (`--output` to a file, or stdout).
101
+ - `slack-report` posts an eval report to Slack via `SLACK_WEBHOOK_URL` (no-op if unset).
102
+ - `doctor` reports config presence plus Postgres, Linear, and Notion connectivity.
103
+
104
+ ## Example flow
105
+
106
+ ```bash
107
+ uv run python examples/linear_memory_flow.py --issue CHEF-308 --comment
108
+ ```
109
+
110
+ See [docs/agent-memory.md](../docs/agent-memory.md) for architecture and OCI deployment.
@@ -0,0 +1,55 @@
1
+ # cursor-dreaming-memory
2
+
3
+ Lightweight agent memory extension for **cursor-dreaming-sdk** (Utrecht Data OS / CHEF-308).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ cd python
9
+ uv sync --extra dev
10
+ uv run dream-memory init # requires Postgres
11
+ ```
12
+
13
+ Optional semantic layer:
14
+
15
+ ```bash
16
+ uv sync --extra semantic
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```python
22
+ from cursor_dreaming_memory import AgentMemory, SessionContext
23
+ from cursor_dreaming_memory.types import MemoryType, MemorySource
24
+
25
+ memory = AgentMemory()
26
+ memory.ensure_schema()
27
+
28
+ ctx = SessionContext.for_dream_eval("2026-06-15T09-00-00Z")
29
+ memory.remember(ctx, MemoryType.OBSERVATION, {"faithfulness": 0.63}, source=MemorySource.SDK)
30
+ ```
31
+
32
+ ## CLI
33
+
34
+ ```bash
35
+ dream-memory init
36
+ dream-memory remember --session-id run-1 --content '{"note":"hello"}'
37
+ dream-memory recall --session-id run-1
38
+ dream-memory linear-ingest CHEF-308
39
+ dream-memory notion-ingest <page_id>
40
+ dream-memory export --session-id run-1 --output run-1.md
41
+ dream-memory slack-report --run-id run-1 --metrics-json metrics.json
42
+ dream-memory doctor
43
+ ```
44
+
45
+ - `export` writes a session's memory records as Markdown (`--output` to a file, or stdout).
46
+ - `slack-report` posts an eval report to Slack via `SLACK_WEBHOOK_URL` (no-op if unset).
47
+ - `doctor` reports config presence plus Postgres, Linear, and Notion connectivity.
48
+
49
+ ## Example flow
50
+
51
+ ```bash
52
+ uv run python examples/linear_memory_flow.py --issue CHEF-308 --comment
53
+ ```
54
+
55
+ See [docs/agent-memory.md](../docs/agent-memory.md) for architecture and OCI deployment.
@@ -0,0 +1,53 @@
1
+ // utrecht-dataos-control-plane-api (Cloudflare Worker, custom domain api.chefgroep.online)
2
+ // Placeholder control-plane API surface + reverse proxy for the agent-memory dashboard.
3
+ // Bindings (kept on deploy via keep_bindings): UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN
4
+
5
+ const DASHBOARD_ORIGIN = 'https://memory.chefgroep.online';
6
+
7
+ addEventListener('fetch', (event) => {
8
+ event.respondWith(handle(event.request));
9
+ });
10
+
11
+ async function handle(request) {
12
+ const url = new URL(request.url);
13
+ const path = url.pathname;
14
+
15
+ // Dashboard, served under the online API at /dashboard
16
+ if (path === '/dashboard' || path === '/dashboard/' || path.startsWith('/dashboard/')) {
17
+ const sub = path.length > '/dashboard'.length ? path.slice('/dashboard'.length) : '/';
18
+ return proxy(DASHBOARD_ORIGIN + sub + url.search, request);
19
+ }
20
+ // Footer links / refresh targets used by the dashboard HTML
21
+ if (path === '/api/metrics' || path === '/healthz') {
22
+ return proxy(DASHBOARD_ORIGIN + path + url.search, request);
23
+ }
24
+
25
+ const hasUpstash =
26
+ typeof UPSTASH_REDIS_REST_URL !== 'undefined' && !!UPSTASH_REDIS_REST_URL;
27
+ const body = {
28
+ service: 'utrecht-dataos-control-plane-api',
29
+ status: 'ok',
30
+ hostname: url.hostname,
31
+ path,
32
+ upstash_bound: hasUpstash,
33
+ dashboard: 'https://api.chefgroep.online/dashboard',
34
+ dashboard_origin: DASHBOARD_ORIGIN,
35
+ note: 'placeholder API surface for Utrecht Data OS control plane',
36
+ ts: new Date().toISOString(),
37
+ };
38
+ return new Response(JSON.stringify(body, null, 2), {
39
+ status: 200,
40
+ headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' },
41
+ });
42
+ }
43
+
44
+ async function proxy(target, request) {
45
+ const upstream = await fetch(target, {
46
+ method: 'GET',
47
+ headers: { accept: request.headers.get('accept') || '*/*' },
48
+ redirect: 'follow',
49
+ });
50
+ const ct = upstream.headers.get('content-type') || 'text/html; charset=utf-8';
51
+ const headers = new Headers({ 'content-type': ct, 'cache-control': 'no-store' });
52
+ return new Response(upstream.body, { status: upstream.status, headers });
53
+ }
@@ -0,0 +1,53 @@
1
+ # Fleet deployment — agent memory
2
+
3
+ Connect every code-agent CLI on the fleet (Cursor, Codex, Claude, OpenCode, Grok)
4
+ to the shared Postgres memory layer.
5
+
6
+ ## Topology
7
+
8
+ | Node | Shape | Role |
9
+ |------|-------|------|
10
+ | `bc-scan-arm` | A1.Flex (ARM, 23GB) | **Memory SSOT** — Postgres + vector (qdrant/weaviate) + llama.cpp |
11
+ | `bc-scan-2` | A1.Flex (ARM) | Inference / inventory worker |
12
+ | `bc-scan-1` | E2.1.Micro (x86) | Scanner |
13
+ | `bc-monitor` | E2.1.Micro (x86) | Monitoring |
14
+ | `sofie` (this host) | local | Dev + orchestration |
15
+
16
+ Postgres SSOT: `postgresql://agentmem:***@100.68.121.19:5432/agent_memory` (Tailscale).
17
+
18
+ ## 1. Sync env to all nodes
19
+
20
+ ```bash
21
+ cd python/deploy/fleet
22
+ ./sync-env.sh # all nodes
23
+ ./sync-env.sh bc-scan-arm # single node
24
+ ```
25
+
26
+ This ships only the memory-related keys to `~/.agent-memory.env` on each node and
27
+ sources it from `~/.bashrc`.
28
+
29
+ ## 2. Install the package on a node
30
+
31
+ ```bash
32
+ ./install-agent-memory.sh bc-scan-2
33
+ ```
34
+
35
+ ## 3. Wire code-agent CLIs
36
+
37
+ Each agent CLI inherits the DSN + keys because its shell sources `~/.agent-memory.env`.
38
+ Agents call memory three ways:
39
+
40
+ | Surface | How |
41
+ |---------|-----|
42
+ | Python | `from cursor_dreaming_memory import AgentMemory` |
43
+ | CLI | `dream-memory remember/recall/linear-ingest/notion-ingest` |
44
+ | Skill | `skills-bundle/shared/agent-memory.md` (drop into any agent skills dir) |
45
+
46
+ `session_type` is auto-detected per agent (cursor / codex / claude / opencode / grok)
47
+ via `SessionContext.from_sdk_payload()`.
48
+
49
+ ## 4. Verify
50
+
51
+ ```bash
52
+ ssh bc-scan-arm 'cd ~/Orgchefgroep/cursor-dreaming-sdk/python && uv run dream-memory recall --limit 5'
53
+ ```
@@ -0,0 +1,14 @@
1
+ [Unit]
2
+ Description=Agent Memory metrics dashboard (always-on)
3
+ After=network-online.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=simple
8
+ WorkingDirectory=%h/cursor-dreaming-memory
9
+ ExecStart=/bin/bash -lc 'set -a; [ -f %h/.agent-memory.env ] && . %h/.agent-memory.env; set +a; exec %h/.local/bin/uv run dream-memory serve --host 0.0.0.0 --port 8787'
10
+ Restart=on-failure
11
+ RestartSec=5
12
+
13
+ [Install]
14
+ WantedBy=default.target
@@ -0,0 +1,10 @@
1
+ [Unit]
2
+ Description=Dream eval + Linear memory sync (oneshot)
3
+ After=network-online.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=oneshot
8
+ WorkingDirectory=%h/cursor-dreaming-memory
9
+ # Source the shell-style env file (export KEY="val") then run the sync flow.
10
+ ExecStart=/bin/bash -lc 'set -a; [ -f %h/.agent-memory.env ] && . %h/.agent-memory.env; set +a; exec %h/.local/bin/uv run python deploy/oci/prefect_flow.py'
@@ -0,0 +1,11 @@
1
+ [Unit]
2
+ Description=Schedule dream eval + Linear memory sync
3
+
4
+ [Timer]
5
+ # Daily 02:00 + Monday 09:00 (mirrors dream_eval_weekly automation)
6
+ OnCalendar=*-*-* 02:00:00
7
+ OnCalendar=Mon *-*-* 09:00:00
8
+ Persistent=true
9
+
10
+ [Install]
11
+ WantedBy=timers.target
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env python3
2
+ """Create/Update a Cloudflare Tunnel that exposes the metrics dashboard on a domain.
3
+
4
+ Requires a Cloudflare API token with:
5
+ - Account → Cloudflare Tunnel: Edit
6
+ - Zone → DNS: Edit (on the target zone)
7
+ - Zone → Zone: Read
8
+
9
+ Env:
10
+ CLOUDFLARE_API_TOKEN (scoped as above)
11
+ CLOUDFLARE_ACCOUNT_ID
12
+ TUNNEL_HOSTNAME e.g. memory.chefgroep.nl
13
+ TUNNEL_NAME default: agent-memory
14
+ LOCAL_SERVICE default: http://localhost:8787
15
+
16
+ Outputs the tunnel run token. Install the connector with:
17
+ sudo cloudflared service install <TOKEN>
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import sys
25
+ import urllib.request
26
+
27
+ API = "https://api.cloudflare.com/client/v4"
28
+
29
+
30
+ def _auth_headers() -> dict:
31
+ """Bearer token, or legacy global-key (X-Auth-Email/Key) if provided."""
32
+ email = os.environ.get("CLOUDFLARE_EMAIL")
33
+ gkey = os.environ.get("CLOUDFLARE_GLOBAL_API_KEY")
34
+ if email and gkey:
35
+ return {"X-Auth-Email": email, "X-Auth-Key": gkey}
36
+ return {"Authorization": f"Bearer {os.environ['CLOUDFLARE_API_TOKEN']}"}
37
+
38
+
39
+ def _req(method: str, path: str, token: str, body: dict | None = None) -> dict:
40
+ data = json.dumps(body).encode() if body is not None else None
41
+ headers = {"Content-Type": "application/json", **_auth_headers()}
42
+ req = urllib.request.Request(
43
+ f"{API}{path}",
44
+ data=data,
45
+ method=method,
46
+ headers=headers,
47
+ )
48
+ with urllib.request.urlopen(req, timeout=30) as resp:
49
+ out = json.loads(resp.read().decode())
50
+ if not out.get("success"):
51
+ raise SystemExit(f"CF API error {method} {path}: {out.get('errors')}")
52
+ return out
53
+
54
+
55
+ def main() -> None:
56
+ token = os.environ.get("CLOUDFLARE_API_TOKEN", "")
57
+ acct = os.environ["CLOUDFLARE_ACCOUNT_ID"]
58
+ hostname = os.environ["TUNNEL_HOSTNAME"]
59
+ name = os.environ.get("TUNNEL_NAME", "agent-memory")
60
+ service = os.environ.get("LOCAL_SERVICE", "http://localhost:8787")
61
+ zone_name = ".".join(hostname.split(".")[-2:])
62
+
63
+ # 1. Resolve zone
64
+ zones = _req("GET", f"/zones?name={zone_name}", token)["result"]
65
+ if not zones:
66
+ raise SystemExit(f"Zone {zone_name} not found / not authorized")
67
+ zone_id = zones[0]["id"]
68
+
69
+ # 2. Create (or reuse) the tunnel — cloudflare-managed config
70
+ existing = _req("GET", f"/accounts/{acct}/cfd_tunnel?name={name}&is_deleted=false", token)
71
+ if existing["result"]:
72
+ tunnel = existing["result"][0]
73
+ tunnel_id = tunnel["id"]
74
+ tok = _req("GET", f"/accounts/{acct}/cfd_tunnel/{tunnel_id}/token", token)["result"]
75
+ else:
76
+ created = _req(
77
+ "POST",
78
+ f"/accounts/{acct}/cfd_tunnel",
79
+ token,
80
+ {"name": name, "config_src": "cloudflare"},
81
+ )["result"]
82
+ tunnel_id = created["id"]
83
+ tok = created["token"]
84
+
85
+ # 3. Configure ingress
86
+ _req(
87
+ "PUT",
88
+ f"/accounts/{acct}/cfd_tunnel/{tunnel_id}/configurations",
89
+ token,
90
+ {
91
+ "config": {
92
+ "ingress": [
93
+ {"hostname": hostname, "service": service},
94
+ {"service": "http_status:404"},
95
+ ]
96
+ }
97
+ },
98
+ )
99
+
100
+ # 4. DNS CNAME → tunnel
101
+ cname = f"{tunnel_id}.cfargotunnel.com"
102
+ recs = _req("GET", f"/zones/{zone_id}/dns_records?name={hostname}", token)["result"]
103
+ payload = {"type": "CNAME", "name": hostname, "content": cname, "proxied": True}
104
+ if recs:
105
+ _req("PUT", f"/zones/{zone_id}/dns_records/{recs[0]['id']}", token, payload)
106
+ else:
107
+ _req("POST", f"/zones/{zone_id}/dns_records", token, payload)
108
+
109
+ print(json.dumps({"tunnel_id": tunnel_id, "hostname": hostname, "url": f"https://{hostname}"}))
110
+ print("TUNNEL_TOKEN=" + tok, file=sys.stderr)
111
+
112
+
113
+ if __name__ == "__main__":
114
+ main()
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ # Install the cursor-dreaming-memory package on a fleet node and verify the DB link.
3
+ # Usage: ./install-agent-memory.sh <node>
4
+ set -euo pipefail
5
+ NODE="${1:?usage: install-agent-memory.sh <node>}"
6
+ REPO_DIR="/home/ubuntu/Orgchefgroep/cursor-dreaming-sdk"
7
+
8
+ ssh "$NODE" bash -s <<'REMOTE'
9
+ set -euo pipefail
10
+ [ -f ~/.agent-memory.env ] && . ~/.agent-memory.env
11
+ command -v uv >/dev/null 2>&1 || curl -LsSf https://astral.sh/uv/install.sh | sh
12
+ mkdir -p ~/Orgchefgroep
13
+ if [ ! -d ~/Orgchefgroep/cursor-dreaming-sdk ]; then
14
+ gh repo clone OnlineChefGroep/cursor-dreaming-sdk ~/Orgchefgroep/cursor-dreaming-sdk 2>/dev/null \
15
+ || git clone https://github.com/OnlineChefGroep/cursor-dreaming-sdk ~/Orgchefgroep/cursor-dreaming-sdk
16
+ fi
17
+ cd ~/Orgchefgroep/cursor-dreaming-sdk/python
18
+ git pull --ff-only 2>/dev/null || true
19
+ uv sync
20
+ echo "--- verifying DB link ---"
21
+ uv run python -c "from cursor_dreaming_memory import AgentMemory; m=AgentMemory(enable_sentry=False); print(m.config.redacted()); m.ensure_schema(); print('schema OK')"
22
+ REMOTE
23
+ echo "Installed agent-memory on $NODE"
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ # Idempotent installer: wire the agent memory layer into one fleet host.
3
+ # Connects every code-agent CLI on the host to the shared OCI Postgres SSOT.
4
+ #
5
+ # Usage (from sofie control node):
6
+ # for h in bc-monitor bc-scan-arm bc-scan-2; do
7
+ # scp -r python "$h:~/cursor-dreaming-memory"
8
+ # ssh "$h" 'bash ~/cursor-dreaming-memory/deploy/fleet/install-memory.sh'
9
+ # done
10
+ #
11
+ # Secrets are read at runtime from ~/.config/agent-memory/.env on each host.
12
+ set -euo pipefail
13
+
14
+ REPO_DIR="${REPO_DIR:-$HOME/cursor-dreaming-memory}"
15
+ ENV_DIR="$HOME/.config/agent-memory"
16
+ ENV_FILE="$ENV_DIR/.env"
17
+
18
+ echo "[*] Installing agent memory on $(hostname)"
19
+
20
+ # 1. uv
21
+ if ! command -v uv >/dev/null 2>&1; then
22
+ echo "[*] Installing uv"
23
+ curl -LsSf https://astral.sh/uv/install.sh | sh
24
+ export PATH="$HOME/.local/bin:$PATH"
25
+ fi
26
+
27
+ # 2. Python deps
28
+ cd "$REPO_DIR"
29
+ uv sync --extra all
30
+
31
+ # 3. Secrets file (filled out-of-band; never committed)
32
+ mkdir -p "$ENV_DIR"
33
+ if [ ! -f "$ENV_FILE" ]; then
34
+ cat > "$ENV_FILE" <<'EOF'
35
+ # Per-host agent memory secrets (chmod 600). Fill these in.
36
+ AGENT_MEMORY_DATABASE_URL=
37
+ LINEAR_API_KEY=
38
+ NOTION_API_KEY=
39
+ CLOUDFLARE_API_TOKEN=
40
+ CLOUDFLARE_ACCOUNT_ID=
41
+ SENTRY_DSN=
42
+ SENTRY_ENVIRONMENT=fleet
43
+ EOF
44
+ chmod 600 "$ENV_FILE"
45
+ echo "[!] Created $ENV_FILE — fill in secrets, then re-run doctor."
46
+ fi
47
+
48
+ # 4. Verify
49
+ set +e
50
+ FLEET_ENV_FILE="$ENV_FILE" uv run dream-memory doctor
51
+ echo "[*] Done. Agents on this host can now: uv run --project $REPO_DIR dream-memory ..."
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # Sync agent-memory env (DSN + secrets) to all fleet nodes over Tailscale.
3
+ # Usage: ./sync-env.sh [node ...] (defaults to all known nodes)
4
+ set -euo pipefail
5
+
6
+ NODES=("${@:-bc-scan-arm bc-scan-2 bc-scan-1 bc-monitor}")
7
+ SRC="${HOME}/.openclaude/.env"
8
+ REMOTE_ENV="/home/ubuntu/.agent-memory.env"
9
+
10
+ if [[ ! -f "$SRC" ]]; then
11
+ echo "ERROR: $SRC not found" >&2
12
+ exit 1
13
+ fi
14
+
15
+ # Only ship the keys the memory layer needs (never the full secrets file).
16
+ KEYS=(AGENT_MEMORY_DATABASE_URL LINEAR_API_KEY LINEAR_TEAM_KEY NOTION_API_KEY NOTION_TOKEN \
17
+ CLOUDFLARE_API_TOKEN CLOUDFLARE_ACCOUNT_ID R2_BUCKET R2_ACCESS_KEY_ID R2_SECRET_ACCESS_KEY R2_ENDPOINT \
18
+ SENTRY_DSN SENTRY_ENVIRONMENT)
19
+
20
+ TMP="$(mktemp)"
21
+ # shellcheck disable=SC1090
22
+ source "$SRC"
23
+ for k in "${KEYS[@]}"; do
24
+ v="${!k:-}"
25
+ [[ -n "$v" ]] && echo "export $k=\"$v\"" >> "$TMP"
26
+ done
27
+
28
+ for node in ${NODES[@]}; do
29
+ echo "→ $node"
30
+ scp -q "$TMP" "$node:$REMOTE_ENV"
31
+ # Ensure interactive + non-interactive shells load it
32
+ ssh "$node" "grep -q 'agent-memory.env' ~/.bashrc 2>/dev/null || echo '[ -f ~/.agent-memory.env ] && . ~/.agent-memory.env' >> ~/.bashrc"
33
+ done
34
+ rm -f "$TMP"
35
+ echo "Done. Memory env synced to: ${NODES[*]}"
@@ -0,0 +1,98 @@
1
+ # OCI deployment — agent memory on Ampere A1
2
+
3
+ Deploy the cursor-dreaming-memory layer on Oracle Cloud Free Tier (ARM).
4
+
5
+ ## Prerequisites
6
+
7
+ - OCI CLI configured (`~/.oci/config`)
8
+ - Ampere A1 compute instance (Ubuntu 22.04+ ARM64)
9
+ - SSH access to the instance
10
+
11
+ ## 1. Provision instance (optional)
12
+
13
+ ```bash
14
+ # List available shapes in your compartment
15
+ oci compute shape list --compartment-id <COMPARTMENT_OCID>
16
+
17
+ # Create instance (example — adjust image OCID for your region)
18
+ oci compute instance launch \
19
+ --availability-domain <AD> \
20
+ --compartment-id <COMPARTMENT_OCID> \
21
+ --shape VM.Standard.A1.Flex \
22
+ --shape-config '{"ocpus":1,"memoryInGBs":6}' \
23
+ --display-name agent-memory-a1 \
24
+ --image-id <UBUNTU_ARM_IMAGE_OCID> \
25
+ --subnet-id <SUBNET_OCID> \
26
+ --assign-public-ip true
27
+ ```
28
+
29
+ ## 2. Copy code to instance
30
+
31
+ ```bash
32
+ rsync -avz python/ ubuntu@<INSTANCE_IP>:~/cursor-dreaming-memory/
33
+ scp .env ubuntu@<INSTANCE_IP>:~/cursor-dreaming-memory/.env
34
+ ```
35
+
36
+ ## 3. Start Postgres
37
+
38
+ On the instance:
39
+
40
+ ```bash
41
+ cd ~/cursor-dreaming-memory/deploy/oci
42
+ docker compose up -d
43
+ ```
44
+
45
+ Postgres listens on `localhost:5432`, database `agent_memory`.
46
+
47
+ ## 4. Install Python package
48
+
49
+ ```bash
50
+ cd ~/cursor-dreaming-memory
51
+ curl -LsSf https://astral.sh/uv/install.sh | sh
52
+ uv sync
53
+ export AGENT_MEMORY_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/agent_memory
54
+ uv run dream-memory init
55
+ ```
56
+
57
+ ## 5. Environment variables
58
+
59
+ ```bash
60
+ export LINEAR_API_KEY=lin_api_...
61
+ export NOTION_API_KEY=secret_...
62
+ export AGENT_MEMORY_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/agent_memory
63
+ ```
64
+
65
+ ## 6. Optional: Prefect scheduled sync
66
+
67
+ ```bash
68
+ uv sync --extra prefect
69
+ uv run python deploy/oci/prefect_flow.py
70
+ ```
71
+
72
+ Runs a daily Linear issue ingest for configured CHEF/GROEP tickets.
73
+
74
+ ## 7. systemd service (optional)
75
+
76
+ ```ini
77
+ # /etc/systemd/system/agent-memory.service
78
+ [Unit]
79
+ Description=Agent Memory Prefect Worker
80
+ After=docker.service
81
+
82
+ [Service]
83
+ Type=simple
84
+ User=ubuntu
85
+ WorkingDirectory=/home/ubuntu/cursor-dreaming-memory
86
+ EnvironmentFile=/home/ubuntu/cursor-dreaming-memory/.env
87
+ ExecStart=/home/ubuntu/.local/bin/uv run python deploy/oci/prefect_flow.py
88
+ Restart=on-failure
89
+
90
+ [Install]
91
+ WantedBy=multi-user.target
92
+ ```
93
+
94
+ ## ARM notes
95
+
96
+ - Use `psycopg[binary]` wheels (included) — no x86-only deps
97
+ - LanceDB optional extra works on aarch64 when installed via pip
98
+ - Keep memory lightweight: 1 OCPU / 6 GB RAM is sufficient for dev