@cairnkeep/cli 1.0.5 → 1.1.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/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +6 -1
- package/README.md +42 -0
- package/docs/building-an-overlay.md +7 -0
- package/docs/domain-knowledge.md +26 -10
- package/docs/operating.md +7 -3
- package/docs/privacy-and-data-flow.md +49 -0
- package/docs/releasing.md +33 -0
- package/docs/storage.md +55 -2
- package/examples/anythingllm/README.md +66 -0
- package/examples/anythingllm/anythingllm-projects.example.json +30 -0
- package/examples/anythingllm/sync_to_anythingllm.py +596 -0
- package/mcp-memory-server/dist/index.js +86 -35
- package/mcp-memory-server/package.json +2 -1
- package/package.json +5 -3
- package/scripts/probe-memory-server.mjs +17 -5
- package/scripts/smoke-mcp-boot.sh +6 -13
- package/scripts/test-package-install.sh +4 -0
- package/templates/env.example.template +6 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes are documented here. This project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [1.1.1] - 2026-07-14
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Ship and resolve the default document-RAG sync helper from the npm package,
|
|
11
|
+
with user-owned XDG config/state paths and legacy-path compatibility.
|
|
12
|
+
- Make repository CI install locked root dependencies before running checks.
|
|
13
|
+
- Make the clean macOS bootstrap test create its target directory explicitly.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Add release-to-npm automation with provenance, tarball, and SBOM artifacts.
|
|
18
|
+
- Document supported clients, platforms, storage placement, and optional data
|
|
19
|
+
flows more explicitly.
|
|
20
|
+
- Add community contribution, support, and conduct templates.
|
|
21
|
+
|
|
22
|
+
## [1.1.0] - 2026-07-13
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Add authenticated remote HTTP memory with stable per-project session routing.
|
|
27
|
+
- Add explicit client routing headers for scopes and document-RAG workspaces.
|
|
28
|
+
- Document local, remote, export, backup, and bearer-token deployment models.
|
|
29
|
+
|
|
30
|
+
## [1.0.5] - 2026-07-13
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Make the npm tarball install self-contained and verify it on clean systems.
|
|
35
|
+
- Preserve executable permissions and Bash 3.2 portability on macOS.
|
|
36
|
+
- Add backup-first uninstall and SQLite-safe memory export/import guidance.
|
|
37
|
+
|
|
38
|
+
[1.1.1]: https://github.com/cairnkeep/cairnkeep/compare/v1.1.0...v1.1.1
|
|
39
|
+
[1.1.0]: https://github.com/cairnkeep/cairnkeep/compare/v1.0.5...v1.1.0
|
|
40
|
+
[1.0.5]: https://github.com/cairnkeep/cairnkeep/compare/v1.0.4...v1.0.5
|
package/CONTRIBUTING.md
CHANGED
|
@@ -15,7 +15,9 @@ Contributions are welcome through GitHub issues and pull requests.
|
|
|
15
15
|
|
|
16
16
|
## Development setup
|
|
17
17
|
|
|
18
|
-
The memory server requires Node.js 18 or newer. Node.js
|
|
18
|
+
The memory server requires Node.js 18 or newer. Node.js 22 or 24 is recommended
|
|
19
|
+
for development; current CI uses Node.js 24 and retains a clean Node.js 18
|
|
20
|
+
compatibility boot check.
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
23
|
git clone https://github.com/cairnkeep/cairnkeep.git
|
|
@@ -47,3 +49,6 @@ endpoints. They are not part of the default offline test suite.
|
|
|
47
49
|
|
|
48
50
|
By contributing, you agree that your contribution is licensed under the
|
|
49
51
|
Apache License 2.0 found in [LICENSE](LICENSE).
|
|
52
|
+
|
|
53
|
+
Release publishing is maintainer-only and documented in
|
|
54
|
+
[docs/releasing.md](docs/releasing.md).
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Cairnkeep
|
|
2
2
|
|
|
3
|
+
[](https://github.com/cairnkeep/cairnkeep/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@cairnkeep/cli)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
3
7
|
> A durable, harness-agnostic **memory + context layer** for coding agents.
|
|
4
8
|
|
|
5
9
|
A *cairn* is a stack of stones left as a trail marker for whoever follows; a
|
|
@@ -20,6 +24,23 @@ a thin routing seam (`route_check`), both of which delegate to
|
|
|
20
24
|
[token-miser](https://github.com/cairnkeep/token-miser), a public
|
|
21
25
|
cairnkeep-org sibling project.
|
|
22
26
|
|
|
27
|
+
## Compatibility
|
|
28
|
+
|
|
29
|
+
Node.js 22 or 24 is recommended. Node.js 18 and 20 remain compatible for the
|
|
30
|
+
1.x line but are end-of-life upstream; the minimum will move in the next major
|
|
31
|
+
release.
|
|
32
|
+
|
|
33
|
+
| Client or platform | Support level |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Claude Code on Linux/macOS | Memory server plus commands, agents, hooks, and launchers |
|
|
36
|
+
| OpenCode on Linux/macOS | Memory server plus commands, plugins, hooks, and launchers |
|
|
37
|
+
| Codex CLI | Memory MCP server; no Cairnkeep operating-layer assets |
|
|
38
|
+
| Other MCP clients | Memory and optional domain-knowledge MCP tools |
|
|
39
|
+
| Native Windows | Not supported by the Bash-based installer; use WSL (not yet CI-verified) |
|
|
40
|
+
|
|
41
|
+
Linux, macOS, Bash 3.2 portability, and a clean Node 18 compatibility install
|
|
42
|
+
are exercised in CI.
|
|
43
|
+
|
|
23
44
|
## Components
|
|
24
45
|
|
|
25
46
|
- **`mcp-memory-server/`** — an MCP server exposing durable, scoped memory
|
|
@@ -85,6 +106,19 @@ cd /path/to/project && cairn doctor
|
|
|
85
106
|
./.ai/start-claude.sh
|
|
86
107
|
```
|
|
87
108
|
|
|
109
|
+
After setup, the basic workflow is intentionally small:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
> /remember Use transactional migrations for schema changes
|
|
113
|
+
Stored as patterns/transactional-migrations.
|
|
114
|
+
|
|
115
|
+
> /recall transactional migrations
|
|
116
|
+
patterns/transactional-migrations: Use transactional migrations for schema changes
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The exact command rendering depends on the client. Any MCP client can call
|
|
120
|
+
`memory_write` and `memory_search` directly.
|
|
121
|
+
|
|
88
122
|
Prefer working from a clone? Build the server with `cd mcp-memory-server && npm
|
|
89
123
|
install && npm run build`, then use `scripts/sync-claude-assets.sh` and
|
|
90
124
|
`bin/cairn` in place of the installed `cairn`.
|
|
@@ -139,8 +173,14 @@ search):
|
|
|
139
173
|
| `CAIRN_EXPLORE_REPO_ROOT` | Default repo root for `context_explore` when no per-call `repo_root` is given |
|
|
140
174
|
| `CAIRN_EXTRA_SETTINGS` | Optional settings/config file the launcher layers onto the harness (wrapper seam) |
|
|
141
175
|
| `CAIRN_ANYTHINGLLM_SYNC_SCRIPT` | Override path to the domain-knowledge sync script (when the integration lives outside the repo) |
|
|
176
|
+
| `CAIRN_ANYTHINGLLM_PROJECTS_FILE` | Override path to the bundled sync script's project configuration |
|
|
177
|
+
| `CAIRN_ANYTHINGLLM_STATE_FILE` | Override path to the bundled sync script's incremental state |
|
|
142
178
|
|
|
143
179
|
Without an API key, search degrades gracefully to substring matching.
|
|
180
|
+
There is no Cairnkeep telemetry. Optional extraction, embeddings, document RAG,
|
|
181
|
+
remote memory, and delegated exploration can send content to endpoints you
|
|
182
|
+
configure. Review [Privacy and data flow](docs/privacy-and-data-flow.md) before
|
|
183
|
+
enabling them.
|
|
144
184
|
|
|
145
185
|
## More
|
|
146
186
|
|
|
@@ -148,7 +188,9 @@ Without an API key, search degrades gracefully to substring matching.
|
|
|
148
188
|
- **Building a private overlay** (wrap cairnkeep for your org/provider) — [docs/building-an-overlay.md](docs/building-an-overlay.md)
|
|
149
189
|
- **Full operating guide** — [docs/operating.md](docs/operating.md)
|
|
150
190
|
- **Memory storage and deployment** — [docs/storage.md](docs/storage.md)
|
|
191
|
+
- **Privacy and data flow** — [docs/privacy-and-data-flow.md](docs/privacy-and-data-flow.md)
|
|
151
192
|
- **Git providers** — [docs/git-providers.md](docs/git-providers.md)
|
|
193
|
+
- **Support** — [SUPPORT.md](SUPPORT.md)
|
|
152
194
|
- **Contributing** — [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
153
195
|
- **Security policy** — [SECURITY.md](SECURITY.md)
|
|
154
196
|
|
|
@@ -107,6 +107,13 @@ All optional, all env-gated — a wrapper turns them on by setting the env:
|
|
|
107
107
|
Point the RAG sync script at your own copy (`CAIRN_ANYTHINGLLM_SYNC_SCRIPT`) so the
|
|
108
108
|
integration scripts live in your overlay, not the core.
|
|
109
109
|
|
|
110
|
+
For a fleet that shares one trusted HTTP service, have the overlay generate
|
|
111
|
+
project-local Claude Code and OpenCode MCP entries with `X-Cairn-Project`,
|
|
112
|
+
`X-Cairn-Scopes`, and `X-Cairn-AnythingLLM-Workspaces`. This preserves local
|
|
113
|
+
project isolation and workspace defaults while keeping the databases and RAG
|
|
114
|
+
credentials on the server host. Keep bearer tokens in environment-backed
|
|
115
|
+
secret storage, not generated project files.
|
|
116
|
+
|
|
110
117
|
## Checklist
|
|
111
118
|
|
|
112
119
|
- [ ] cairnkeep pinned to a version; no core files copied or patched
|
package/docs/domain-knowledge.md
CHANGED
|
@@ -28,7 +28,9 @@ work exactly the same without them.
|
|
|
28
28
|
|---|---|
|
|
29
29
|
| `ANYTHINGLLM_API_KEY` | **Required** for the domain-knowledge tools. Unset → the tools error at call time (everything else works). |
|
|
30
30
|
| `ANYTHINGLLM_BASE_URL` | AnythingLLM base URL. Default `http://localhost:3001`. |
|
|
31
|
-
| `CAIRN_ANYTHINGLLM_SYNC_SCRIPT` |
|
|
31
|
+
| `CAIRN_ANYTHINGLLM_SYNC_SCRIPT` | Optional path to a custom document-sync script. Unset -> `domain_knowledge_sync` uses the bundled deployment-neutral example. |
|
|
32
|
+
| `CAIRN_ANYTHINGLLM_PROJECTS_FILE` | Optional config path for the bundled sync script. Default `${XDG_CONFIG_HOME:-~/.config}/cairnkeep/anythingllm-projects.json`. |
|
|
33
|
+
| `CAIRN_ANYTHINGLLM_STATE_FILE` | Optional state path for the bundled sync script. Default `${XDG_STATE_HOME:-~/.local/state}/cairnkeep/anythingllm-sync.json`. |
|
|
32
34
|
|
|
33
35
|
The workspaces the tools target come from the project's **memory config** — the
|
|
34
36
|
first of `.agent/memory.json`, `.opencode/memory.json`, `.claude/memory.json`, or
|
|
@@ -45,6 +47,18 @@ first of `.agent/memory.json`, `.opencode/memory.json`, `.claude/memory.json`, o
|
|
|
45
47
|
configured workspace that is not `engineering-patterns` (the conventional shared
|
|
46
48
|
workspace). With no workspace given and none configured, it errors.
|
|
47
49
|
|
|
50
|
+
In local stdio mode, that config is read from the client project's working
|
|
51
|
+
directory. In remote HTTP mode, the server cannot read files from the client
|
|
52
|
+
PC. Configure `ANYTHINGLLM_BASE_URL`, `ANYTHINGLLM_API_KEY`, and any sync script
|
|
53
|
+
on the HTTP server host, then send the project workspaces in the
|
|
54
|
+
`X-Cairn-AnythingLLM-Workspaces` session header. See
|
|
55
|
+
[Memory storage and deployment](storage.md#per-project-remote-sessions).
|
|
56
|
+
|
|
57
|
+
The HTTP server performs queries and runs the sync script on its own host. A
|
|
58
|
+
remote sync script must therefore obtain project documents from a server-side
|
|
59
|
+
checkout, object store, or git host; it cannot read an arbitrary client PC's
|
|
60
|
+
working tree.
|
|
61
|
+
|
|
48
62
|
## Setup (query)
|
|
49
63
|
|
|
50
64
|
```bash
|
|
@@ -61,10 +75,10 @@ returns a grounded answer.
|
|
|
61
75
|
|
|
62
76
|
## Setup (sync / embedding)
|
|
63
77
|
|
|
64
|
-
`domain_knowledge_sync` shells out to a document-upload/embed script.
|
|
65
|
-
|
|
66
|
-
deployment-specific,
|
|
67
|
-
at
|
|
78
|
+
`domain_knowledge_sync` shells out to a document-upload/embed script. Cairnkeep
|
|
79
|
+
ships a deployment-neutral example that reads its project mapping from a config
|
|
80
|
+
file. For deployment-specific authentication, checkout rules, or document
|
|
81
|
+
selection, keep a customized script in your overlay and point Cairnkeep at it:
|
|
68
82
|
|
|
69
83
|
```bash
|
|
70
84
|
CAIRN_ANYTHINGLLM_SYNC_SCRIPT=/abs/path/to/your/sync_to_anythingllm.py
|
|
@@ -74,11 +88,13 @@ The script receives the workspace slug and is expected to upload + embed the
|
|
|
74
88
|
project's documents into that AnythingLLM workspace. See
|
|
75
89
|
[building-an-overlay.md](building-an-overlay.md) for the wrapper pattern.
|
|
76
90
|
|
|
77
|
-
|
|
78
|
-
[`examples/anythingllm/`](../examples/anythingllm/): an incremental
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
The bundled default lives in
|
|
92
|
+
[`examples/anythingllm/`](../examples/anythingllm/): an incremental,
|
|
93
|
+
SHA-256-tracked multi-project sync script plus a config schema. Put a customized
|
|
94
|
+
copy of the example JSON at the default user config path, or set
|
|
95
|
+
`CAIRN_ANYTHINGLLM_PROJECTS_FILE`. Existing custom scripts with configuration
|
|
96
|
+
and state beside the script retain that legacy behavior. To customize the
|
|
97
|
+
implementation itself, set `CAIRN_ANYTHINGLLM_SYNC_SCRIPT` to the adapted copy.
|
|
82
98
|
|
|
83
99
|
## Not using RAG?
|
|
84
100
|
|
package/docs/operating.md
CHANGED
|
@@ -156,6 +156,8 @@ vendor or host.
|
|
|
156
156
|
| `ANYTHINGLLM_API_KEY` | Required to enable the optional `domain_knowledge_*` RAG tools (unset → those tools error at call time; nothing else affected). See [domain-knowledge.md](domain-knowledge.md) |
|
|
157
157
|
| `ANYTHINGLLM_BASE_URL` | AnythingLLM base URL for `domain_knowledge_*` (default `http://localhost:3001`) |
|
|
158
158
|
| `CAIRN_ANYTHINGLLM_SYNC_SCRIPT` | Override path to the `domain_knowledge_sync` document-sync script (unset → in-repo default) |
|
|
159
|
+
| `CAIRN_ANYTHINGLLM_PROJECTS_FILE` | Override path to the bundled sync script's project configuration |
|
|
160
|
+
| `CAIRN_ANYTHINGLLM_STATE_FILE` | Override path to the bundled sync script's incremental state |
|
|
159
161
|
|
|
160
162
|
### Domain knowledge (RAG via AnythingLLM, opt-in)
|
|
161
163
|
|
|
@@ -267,9 +269,11 @@ is guarded and **fails closed**:
|
|
|
267
269
|
Requests without a valid bearer token get `401`; requests with an unexpected
|
|
268
270
|
`Host` header get `403`. Keep HTTP mode bound to `127.0.0.1` unless you have a
|
|
269
271
|
specific reason to expose it, and use a long random token. HTTP mode has no
|
|
270
|
-
per-user ACL or tenant isolation
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
per-user ACL or tenant isolation. Clients may bind sessions to separate project
|
|
273
|
+
databases with validated `X-Cairn-Project` routing metadata, but that metadata
|
|
274
|
+
is not an authorization boundary. See [Memory storage and deployment](storage.md)
|
|
275
|
+
for the placement rules, client registration, TLS requirements, project headers,
|
|
276
|
+
and backup boundaries.
|
|
273
277
|
|
|
274
278
|
## The workflow
|
|
275
279
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Privacy and data flow
|
|
2
|
+
|
|
3
|
+
Cairnkeep has no telemetry, analytics collector, hosted control plane, or
|
|
4
|
+
automatic remote-service discovery. A default local stdio installation stores
|
|
5
|
+
memory in SQLite on the machine running the MCP server and makes no model or RAG
|
|
6
|
+
request unless the corresponding endpoint and credential are configured.
|
|
7
|
+
|
|
8
|
+
## Data flows
|
|
9
|
+
|
|
10
|
+
| Feature | Data that can leave the server machine | Destination |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Local substring search | None | Local SQLite only |
|
|
13
|
+
| Embedding-ranked search | Stored memory values that are not cached, plus the search query | `CAIRN_MEMORY_EMBEDDING_URL` or `CAIRN_LLM_API_URL` |
|
|
14
|
+
| `memory_extract` | The transcript supplied to the tool | `CAIRN_LLM_API_URL` |
|
|
15
|
+
| `domain_knowledge_query` | Workspace slug and query | `ANYTHINGLLM_BASE_URL` |
|
|
16
|
+
| `domain_knowledge_sync` | Files selected by the sync configuration | `ANYTHINGLLM_BASE_URL` |
|
|
17
|
+
| `route_check` | A health request, with no memory or prompt content | `CAIRN_ROUTE_ENDPOINT` |
|
|
18
|
+
| `context_explore` | Repository path and query are passed to the configured local executable | `CAIRN_EXPLORE_BINARY`; any further data flow is controlled by that tool |
|
|
19
|
+
| Remote HTTP memory | MCP requests and responses, including memory content | The explicitly registered Cairnkeep HTTP server |
|
|
20
|
+
|
|
21
|
+
Model endpoints may be local or remote. Cairnkeep cannot determine a provider's
|
|
22
|
+
retention, training, or logging policy; verify it before sending confidential
|
|
23
|
+
material. Disabling `CAIRN_LLM_API_KEY`, `ANYTHINGLLM_API_KEY`, remote HTTP
|
|
24
|
+
registration, and delegated tools keeps the core memory workflow local.
|
|
25
|
+
|
|
26
|
+
## Data at rest
|
|
27
|
+
|
|
28
|
+
Memories are stored in SQLite databases. They are not encrypted by Cairnkeep at
|
|
29
|
+
the application layer. Use operating-system disk encryption, restrictive file
|
|
30
|
+
permissions, encrypted backups, and host access controls appropriate to the
|
|
31
|
+
sensitivity of the material. SQLite `-wal` and `-shm` sidecars and exported
|
|
32
|
+
archives can contain sensitive content too.
|
|
33
|
+
|
|
34
|
+
Project-scoped and named/global database locations are documented in
|
|
35
|
+
[Memory storage and deployment](storage.md). A remote client stores memory on
|
|
36
|
+
the remote server host; changing a storage environment variable on the client
|
|
37
|
+
does not relocate that server's databases.
|
|
38
|
+
|
|
39
|
+
## Credentials and transport
|
|
40
|
+
|
|
41
|
+
Keep API keys and bearer tokens out of repositories and command output. Load
|
|
42
|
+
them from a secret manager or protected environment file. For remote HTTP mode,
|
|
43
|
+
use TLS or an encrypted private network and keep the raw listener on loopback.
|
|
44
|
+
One HTTP bearer token grants access to the entire server; Cairnkeep does not
|
|
45
|
+
provide tenant isolation or per-scope authorization.
|
|
46
|
+
|
|
47
|
+
Before sharing diagnostics, remove credentials, private endpoints, database
|
|
48
|
+
files, memory values, local paths, and project names. Report vulnerabilities
|
|
49
|
+
through the private channel in [SECURITY.md](../SECURITY.md).
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Publishing is driven by a GitHub Release. Maintainers do not publish the package
|
|
4
|
+
from a workstation.
|
|
5
|
+
|
|
6
|
+
## Release contract
|
|
7
|
+
|
|
8
|
+
1. Update the root `package.json` version and `CHANGELOG.md` on a pull request.
|
|
9
|
+
2. Run `npm ci`, `npm run check:public`, and
|
|
10
|
+
`npm --prefix mcp-memory-server test`.
|
|
11
|
+
3. Merge only after every required CI check passes.
|
|
12
|
+
4. Publish a GitHub Release whose tag is exactly `v<package.json version>`.
|
|
13
|
+
5. The `Publish release` workflow checks out that immutable tag, repeats the
|
|
14
|
+
tests, and publishes `@cairnkeep/cli` with npm provenance.
|
|
15
|
+
6. The workflow attaches the npm tarball, a CycloneDX SBOM, and SHA-256 checksums
|
|
16
|
+
to the GitHub Release.
|
|
17
|
+
|
|
18
|
+
Stable versions must use a stable GitHub Release and publish to npm's `latest`
|
|
19
|
+
tag. SemVer prerelease versions must use a GitHub prerelease and publish to
|
|
20
|
+
`next`. A mismatch fails before publication.
|
|
21
|
+
|
|
22
|
+
The workflow is safe to rerun: it skips `npm publish` when that exact version is
|
|
23
|
+
already present, then regenerates and replaces the release artifacts.
|
|
24
|
+
|
|
25
|
+
## Repository configuration
|
|
26
|
+
|
|
27
|
+
The repository must provide an `NPM_TOKEN` Actions secret authorized to publish
|
|
28
|
+
`@cairnkeep/cli`. Keep that credential out of local files and rotate it according
|
|
29
|
+
to the npm account's security policy. The workflow grants only `contents: write`
|
|
30
|
+
and `id-token: write`; the latter is required for npm provenance.
|
|
31
|
+
|
|
32
|
+
Treat a published version as immutable. If a release is wrong, fix it in a new
|
|
33
|
+
version rather than moving its tag or replacing the npm package.
|
package/docs/storage.md
CHANGED
|
@@ -53,12 +53,34 @@ With this topology, the databases are on the server host, not the client PC.
|
|
|
53
53
|
Setting `CAIRN_AGENTFS_BASE_DIR` on the client does not redirect a remote
|
|
54
54
|
server; set it in the server service environment.
|
|
55
55
|
|
|
56
|
+
### Per-project remote sessions
|
|
57
|
+
|
|
58
|
+
Remote clients can bind an MCP session to a stable project identity and send
|
|
59
|
+
the memory configuration that a local server would read from `memory.json`:
|
|
60
|
+
|
|
61
|
+
| Header | Purpose |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `X-Cairn-Project` | Kebab-case project identity, up to 64 characters |
|
|
64
|
+
| `X-Cairn-Scopes` | Comma-separated scopes used when a tool reads scope `all` |
|
|
65
|
+
| `X-Cairn-AnythingLLM-Workspaces` | Comma-separated AnythingLLM workspace slugs; the first non-`engineering-patterns` workspace is the default |
|
|
66
|
+
|
|
67
|
+
When `X-Cairn-Project` is present, `project` scope is stored at
|
|
68
|
+
`${CAIRN_AGENTFS_BASE_DIR}/projects/<project-id>.db`. Sessions with different
|
|
69
|
+
project identities therefore do not share project memory. Without the header,
|
|
70
|
+
HTTP mode retains the legacy behavior and resolves `project` from the server
|
|
71
|
+
working directory.
|
|
72
|
+
|
|
73
|
+
These headers are session routing metadata, not authorization. The bearer
|
|
74
|
+
token still grants access to the entire server, including the ability to choose
|
|
75
|
+
another valid project identity. Use separate server instances for separate
|
|
76
|
+
trust domains.
|
|
77
|
+
|
|
56
78
|
HTTP mode is one trusted storage domain:
|
|
57
79
|
|
|
58
80
|
- One bearer token grants access to every exposed memory tool.
|
|
59
81
|
- There is no per-user ACL, tenant isolation, or client-specific filesystem.
|
|
60
|
-
- `
|
|
61
|
-
|
|
82
|
+
- Sessions without `X-Cairn-Project` share the project database resolved from
|
|
83
|
+
the server process's working directory.
|
|
62
84
|
- Use one server instance per isolation boundary. Do not offer one instance to
|
|
63
85
|
mutually untrusted users.
|
|
64
86
|
- Keep the Cairnkeep listener on loopback behind a TLS reverse proxy, or use an
|
|
@@ -107,8 +129,18 @@ claude mcp remove cairn-memory -s user 2>/dev/null || true
|
|
|
107
129
|
claude mcp add --transport http -s user \
|
|
108
130
|
cairn-memory "$CAIRN_MEMORY_REMOTE_URL" \
|
|
109
131
|
--header "Authorization: Bearer $CAIRN_MEMORY_HTTP_TOKEN"
|
|
132
|
+
|
|
133
|
+
codex mcp remove cairn-memory 2>/dev/null || true
|
|
134
|
+
codex mcp add cairn-memory \
|
|
135
|
+
--url "$CAIRN_MEMORY_REMOTE_URL" \
|
|
136
|
+
--bearer-token-env-var CAIRN_MEMORY_HTTP_TOKEN
|
|
110
137
|
```
|
|
111
138
|
|
|
139
|
+
Codex reads the bearer token from the named environment variable when it
|
|
140
|
+
starts. Do not run `codex mcp login cairn-memory`: that command starts an OAuth
|
|
141
|
+
flow, while Cairnkeep intentionally uses a static bearer token and advertises
|
|
142
|
+
no OAuth authorization endpoint.
|
|
143
|
+
|
|
112
144
|
OpenCode is configured separately in its per-user `opencode.json`. It supports
|
|
113
145
|
environment references in remote MCP headers, so the token does not need to be
|
|
114
146
|
written literally into the JSON:
|
|
@@ -132,3 +164,24 @@ Ensure the secret-manager bootstrap exports `CAIRN_MEMORY_HTTP_TOKEN` before
|
|
|
132
164
|
OpenCode starts. Preserve any other keys already present in `opencode.json`
|
|
133
165
|
rather than replacing the whole file. The URL, token, private host names, and
|
|
134
166
|
device-specific configuration must never be committed to this public project.
|
|
167
|
+
|
|
168
|
+
For distinct project memory, install a project-local MCP entry with the same
|
|
169
|
+
URL and authorization header plus the three routing headers. Claude Code
|
|
170
|
+
expands `${VAR}` references in project `.mcp.json` URL and header values;
|
|
171
|
+
OpenCode uses `{env:VAR}` references. A private overlay should generate and
|
|
172
|
+
merge these files so secrets remain in the process environment rather than the
|
|
173
|
+
repository.
|
|
174
|
+
|
|
175
|
+
For Codex, put the routing configuration in the trusted project's private
|
|
176
|
+
`.codex/config.toml` and exclude it from version control:
|
|
177
|
+
|
|
178
|
+
```toml
|
|
179
|
+
[mcp_servers.cairn-memory]
|
|
180
|
+
url = "https://memory.example.com/mcp"
|
|
181
|
+
bearer_token_env_var = "CAIRN_MEMORY_HTTP_TOKEN"
|
|
182
|
+
|
|
183
|
+
[mcp_servers.cairn-memory.http_headers]
|
|
184
|
+
"X-Cairn-Project" = "example-project"
|
|
185
|
+
"X-Cairn-Scopes" = "identity,personal,project"
|
|
186
|
+
"X-Cairn-AnythingLLM-Workspaces" = "engineering-patterns"
|
|
187
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# AnythingLLM sync — reference example
|
|
2
|
+
|
|
3
|
+
The bundled reference implementation of the document-sync script that
|
|
4
|
+
Cairnkeep's `domain_knowledge_sync` tool shells out to. It is a usable,
|
|
5
|
+
deployment-neutral starting point; copy and adapt it when endpoint,
|
|
6
|
+
authentication, or include/exclude rules are deployment-specific.
|
|
7
|
+
|
|
8
|
+
See [`../../docs/domain-knowledge.md`](../../docs/domain-knowledge.md) for the
|
|
9
|
+
full RAG picture.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
Incrementally syncs each configured project's docs into its own AnythingLLM
|
|
14
|
+
workspace: creates the workspace, uploads changed files (tracked by sha256),
|
|
15
|
+
embeds them, and removes docs that disappeared. Supports `--dry-run`, `--full`,
|
|
16
|
+
`--replace`, `--rebuild-state`, `--list`, and `--project <slug>`.
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
1. Requires Python 3 and `requests` (`pip install requests`).
|
|
21
|
+
2. Copy the config to the default user config location and fill in your
|
|
22
|
+
projects:
|
|
23
|
+
```bash
|
|
24
|
+
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/cairnkeep"
|
|
25
|
+
cp anythingllm-projects.example.json \
|
|
26
|
+
"${XDG_CONFIG_HOME:-$HOME/.config}/cairnkeep/anythingllm-projects.json"
|
|
27
|
+
# edit: set each project's absolute path, slug, and include/exclude globs
|
|
28
|
+
```
|
|
29
|
+
3. Point at your AnythingLLM instance:
|
|
30
|
+
```bash
|
|
31
|
+
export ANYTHINGLLM_BASE_URL=http://localhost:3001 # default
|
|
32
|
+
export ANYTHINGLLM_API_KEY=<your AnythingLLM API key>
|
|
33
|
+
```
|
|
34
|
+
4. First upload, then keep it in sync:
|
|
35
|
+
```bash
|
|
36
|
+
python3 sync_to_anythingllm.py --full --project my-project
|
|
37
|
+
python3 sync_to_anythingllm.py # incremental, all projects
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Wiring into cairnkeep
|
|
41
|
+
|
|
42
|
+
The installed server uses this script by default. To use an adapted copy, set:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
CAIRN_ANYTHINGLLM_SYNC_SCRIPT=/abs/path/to/sync_to_anythingllm.py
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Override the user-owned configuration or state locations when needed:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
CAIRN_ANYTHINGLLM_PROJECTS_FILE=/abs/path/to/anythingllm-projects.json
|
|
52
|
+
CAIRN_ANYTHINGLLM_STATE_FILE=/abs/path/to/anythingllm-sync.json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For backward compatibility, an existing `anythingllm-projects.json` beside a
|
|
56
|
+
customized script and its `.anythingllm-sync.json` state are still used when the
|
|
57
|
+
override variables are unset.
|
|
58
|
+
|
|
59
|
+
## Files
|
|
60
|
+
|
|
61
|
+
| File | Committed? | Notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `sync_to_anythingllm.py` | yes | the script |
|
|
64
|
+
| `anythingllm-projects.example.json` | yes | schema template |
|
|
65
|
+
| `anythingllm-projects.json` | **no** | User-owned config; defaults under the XDG config directory |
|
|
66
|
+
| `anythingllm-sync.json` | **no** | Machine-local SHA-256 state; defaults under the XDG state directory |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projects": [
|
|
3
|
+
{
|
|
4
|
+
"slug": "my-project",
|
|
5
|
+
"display_name": "My Project Documentation",
|
|
6
|
+
"path": "/abs/path/to/my-project",
|
|
7
|
+
"patterns": [
|
|
8
|
+
"README.md",
|
|
9
|
+
"docs/**/*.md"
|
|
10
|
+
],
|
|
11
|
+
"exclude_patterns": [
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"LICENSE.md"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"slug": "another-project",
|
|
18
|
+
"display_name": "Another Project Docs",
|
|
19
|
+
"path": "/abs/path/to/another-project",
|
|
20
|
+
"patterns": [
|
|
21
|
+
"AGENTS.md",
|
|
22
|
+
"docs/**/*.md",
|
|
23
|
+
".planning/wiki/**/*.md"
|
|
24
|
+
],
|
|
25
|
+
"exclude_patterns": [
|
|
26
|
+
".planning/wiki/tmp/**"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|