feat: .shared-memory-project file convention for repo-rooted project ID
Replaces "per-machine X-Project-Key header" as the default way to tell Claude Code which shared-memory project a repo belongs to. Commit a single-line `.shared-memory-project` text file at the repo root; every collaborator's Claude Code reads it at session start and attaches all memories + snippets to the same shared project. No per-machine config required. Changes: - New file convention documented in README (resolution order, format, authoring snippet, rationale for plain-text over JSON). - project.identify tool description now leads with "check .shared-memory-project at the repo root", with inference as fallback. - memory.write description mentions the file as the canonical source for project keys. - Project detail page in the Web UI shows a copy-paste `echo > file` command so users see exactly what to add to their repo. - Added .shared-memory-project to this repo (content: `shared-memory`). Resolution precedence is: explicit tool arg → .shared-memory-project → X-Project-Key header → inference. The file beats the header because repo context is more specific than machine context. This is a soft convention — Claude has to read the file. Directive tool descriptions make this very likely; a Claude Code skill would make it bulletproof, deferred until we see whether the description alone is enough. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -201,6 +201,26 @@ export default async function ProjectDetailPage({
|
||||
}
|
||||
/>
|
||||
|
||||
<Card className="mb-6">
|
||||
<CardHeader className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium">Auto-identify this project</span>
|
||||
<span className="text-xs text-fg-subtle">.shared-memory-project</span>
|
||||
</CardHeader>
|
||||
<CardBody className="space-y-2 text-sm">
|
||||
<p className="text-fg-muted">
|
||||
Commit a one-line text file at the repo root so every Claude Code
|
||||
session opened in this repo automatically targets this project —
|
||||
no per-machine config needed.
|
||||
</p>
|
||||
<pre className="!whitespace-pre-wrap text-xs">{`echo "${project.key}" > .shared-memory-project`}</pre>
|
||||
<p className="text-xs text-fg-subtle">
|
||||
Commit it. The directive tool descriptions tell Claude to read this
|
||||
file at session start before falling back to inference or the
|
||||
<code className="mx-1">X-Project-Key</code>header.
|
||||
</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{shareRows.length > 0 || isOwner ? (
|
||||
<Card className="mb-6">
|
||||
<CardHeader className="flex items-center justify-between">
|
||||
|
||||
@@ -156,14 +156,14 @@ function withDefaultProject(
|
||||
const projectIdentify: ToolDef = {
|
||||
name: "project.identify",
|
||||
description:
|
||||
"Call ONCE near the start of every session that has a project context — a repo you're working in, a service you're debugging, etc. — to register or look up that project so subsequent project-scoped memories attach correctly. Use a stable `key` you can reproduce next session (repo name, repo URL, or working directory basename). Returns shared projects you have access to in addition to your own; when an owned and a shared project would both match the same key, the owned one wins (a server-side warning is logged so the collision is debuggable). Skip if the work is purely scratch / not tied to a specific codebase.",
|
||||
"Call ONCE near the start of every session that has a project context — a repo you're working in, a service you're debugging, etc. — to register or look up that project so subsequent project-scoped memories attach correctly. **Look up the key in this order:** (1) `.shared-memory-project` at the repo root (single-line text file with just the project key; walk up from cwd to find it — same lookup style as `.gitignore` / `.nvmrc`). (2) If no file, fall back to a stable inference: repo name, git remote slug, or working directory basename. The file convention exists so teams sharing a repo all hit the same shared project automatically — prefer it over guessing. Returns shared projects you have access to in addition to your own; when an owned and a shared project would both match the same key, the owned one wins (a server-side warning is logged so the collision is debuggable). Skip if the work is purely scratch / not tied to a specific codebase.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
key: {
|
||||
type: "string",
|
||||
description:
|
||||
"Stable project identifier. Recommended: repo name, repo URL, or any string the caller can reproduce across sessions.",
|
||||
"Stable project identifier. First check `.shared-memory-project` at the repo root (one line of plain text, that line IS the key) — that's the canonical source when present. Otherwise use repo name, repo URL, or any string the caller can reproduce across sessions.",
|
||||
},
|
||||
display_name: {
|
||||
type: "string",
|
||||
@@ -317,7 +317,7 @@ const projectIdentify: ToolDef = {
|
||||
const memoryWrite: ToolDef = {
|
||||
name: "memory.write",
|
||||
description:
|
||||
"Save a durable fact, preference, or decision that ANY future Claude Code session on ANY of this user's machines should know. Call this when the user shares something that meets ALL of: (1) likely to matter beyond this conversation, (2) not derivable from reading current code/git, (3) would surprise a future you if forgotten. Examples: 'I use HAProxy at home' (user-scope), 'we chose Drizzle over Prisma because of bundle size' (project-scope), 'our prod DB is at db.example.com' (user-scope reference). Use scope='user' for facts about the human or their infra; scope='project' for facts tied to a specific codebase (always preceded by project.identify). In shared projects (i.e. ones surfaced by project.identify with `shared: true`), anyone with rw access can write — your memory becomes visible to every member of every group the project is shared with. Defaults `project` to the X-Project-Key header value if not supplied. Sensitive info (API keys, credentials, connection strings the user actively shares with you) IS appropriate to save here — this server is OIDC-gated and per-user; safer than writing to local container files. DO NOT use for: transient task state, this-session-only scratch notes, or container-specific facts (those belong in the built-in file-based memory at ~/.claude/.../memory/). Tags help retrieval.",
|
||||
"Save a durable fact, preference, or decision that ANY future Claude Code session on ANY of this user's machines should know. Call this when the user shares something that meets ALL of: (1) likely to matter beyond this conversation, (2) not derivable from reading current code/git, (3) would surprise a future you if forgotten. Examples: 'I use HAProxy at home' (user-scope), 'we chose Drizzle over Prisma because of bundle size' (project-scope), 'our prod DB is at db.example.com' (user-scope reference). Use scope='user' for facts about the human or their infra; scope='project' for facts tied to a specific codebase (always preceded by project.identify; project key should come from `.shared-memory-project` at the repo root when present). In shared projects (i.e. ones surfaced by project.identify with `shared: true`), anyone with rw access can write — your memory becomes visible to every member of every group the project is shared with. Defaults `project` to the X-Project-Key header value if not supplied. Sensitive info (API keys, credentials, connection strings the user actively shares with you) IS appropriate to save here — this server is OIDC-gated and per-user; safer than writing to local container files. DO NOT use for: transient task state, this-session-only scratch notes, or container-specific facts (those belong in the built-in file-based memory at ~/.claude/.../memory/). Tags help retrieval.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
|
||||
Reference in New Issue
Block a user