Skip to content

fix(project): name the project a memory belongs to, and refuse to guess it - #558

Merged
kevintseng merged 7 commits into
mainfrom
fix/project-attribution
Oct 5, 2026
Merged

kevintseng merged 7 commits into
mainfrom
fix/project-attribution

Conversation

@kevintseng

@kevintseng kevintseng commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #527

What changes for you

  • A project name is stored and looked up exactly as you wrote it (no trimming, no Unicode normalising), so a lesson or task state is found again under the same spelling.
  • An empty project, or one written as a path (/Users/me/proj, C:\proj, a/b, ./foo, ~/foo), is refused with an error naming the field by learn, task_state and briefing over MCP, by POST /v1/learn, and by memesh learn, memesh task, memesh briefing and memesh import --notes.
  • POST /v1/learn requires project; without it the request answers 400 and nothing is written. memesh learn takes --project (without it, the working directory's project, as before). Over MCP, a call without a project uses the session's bound project, as it already does.
  • GET /v1/task-state and GET /v1/briefing-index still read a path-shaped project key stored by an older version.
  • The PreCompact hook no longer saves a snapshot when its input has no usable session id or folder; it records why instead.

Checks

  • npm run verify green on the final tree.
  • Tests cover the HTTP 400, the CLI refusals, the exact-spelling round trip, the legacy reads and the PreCompact skips.

…ss it

- `learn` takes an optional `project` over MCP and `memesh learn --project`
  (omitted, it uses the current directory's project, as `task_state` and
  `briefing` do). `POST /v1/learn` requires `project`: the HTTP server's
  own directory is never the caller's project, so a missing one is a 400
  and nothing is written.
- An MCP server running in MeMesh's own directory (Codex starts plugin
  servers in the plugin's directory) cannot tell which project the caller
  is in: `learn`, `task_state` and `briefing` without `project` are refused
  there with one line saying to pass the project the SessionStart briefing
  gave. A server started in a workspace (Claude Code) is unchanged.
- `learn`, `task_state`, `briefing` and the CLI's `task`, `briefing`,
  `import --notes` and `learn` refuse an empty or path-shaped project,
  absolute or relative. A project name is otherwise used exactly as given
  everywhere, so a stored task state or lesson is found again under the
  same spelling.
- `GET /v1/task-state` and `GET /v1/briefing-index` still read an existing
  path-shaped project key exactly as stored; writes to one are refused.
- The PreCompact hook skips a payload whose `session_id` or `cwd` is
  missing, blank or not a string, and records why.

Refs #527
# Conflicts:
#	CHANGELOG.md
#	dist/mcp/THIRD_PARTY_NOTICES.txt
#	dist/mcp/server.js.map
#	dist/transports/mcp/handlers.d.ts.map
#	dist/transports/mcp/handlers.js.map
…t errors

- A project name longer than 200 characters is refused by `learn`,
  `task_state`, `briefing` and the CLI's `task`, `learn` and `briefing`,
  the same limit the read routes already applied; before, the CLI stored
  a key that the dashboard and MCP could not read back.
- When a project cannot be determined from the working directory, the
  error says how to find it: run `memesh briefing --json` in the workspace
  and pass its `project` field.
- The exported OpenAI tool schema for `learn` says that HTTP requires
  `project`.
- The changelog and API reference state the rules precisely: they apply
  to `learn`, `task_state` and `briefing` (messaging and
  `kg rename-project` are unchanged), and a server run from the checkout
  it is started in counts as MeMesh's own directory.

Refs #527
Merges the project-attribution branch onto main as it stands now. Main
already resolves an MCP call's project from the session's binding and
refuses an unbound call, so this keeps main's way of choosing a project
and drops the branch's own-directory check, which main makes unnecessary.
What it adds:

- A project name is stored and looked up exactly as written, and an empty
  or path-shaped name is refused by learn, task_state and briefing on MCP,
  HTTP and the CLI.
- POST /v1/learn requires project; memesh learn takes --project.
- GET /v1/task-state and /v1/briefing-index still read a path-shaped key
  stored by an older version.
- The PreCompact hook skips, and records why, when its input has no usable
  session id or folder.

Refs #527
…ample

- GET /v1/task-state and /v1/briefing-index take their project length
  limit from the same constant the writers use (still 200).
- The API reference no longer calls error and fix the only required fields
  of a lesson for POST /v1/learn, which also requires project.
- The exported learn schema is tested against what POST /v1/learn accepts.

Refs #527
Brings in the credential redaction that landed on main (#569). Where both
touched the same lines, the CLI's learn and task writes keep the
validated --project value and the one-line refusal for a write next to
part of a private key; the HTTP read routes, doctor routes and the
PreCompact title keep both the masking and the project checks.

Refs #527
@kevintseng
kevintseng merged commit a6f856c into main Oct 5, 2026
12 checks passed
2233admin pushed a commit to 2233admin/claude-code-buddy that referenced this pull request Oct 10, 2026
Each branch fixes one reported issue; this merge combines them on top of
the credential redaction (PCIRCLE-AI#569) and exact project name (PCIRCLE-AI#558) changes.

- PCIRCLE-AI#514 remind a Codex thread again once the host that accepted it ended
- PCIRCLE-AI#534 export-schema describes the message tool's session fields
- PCIRCLE-AI#568 open a database whose index rebuild is waiting to retry
- PCIRCLE-AI#560 the Bash guard check reports a guard store it cannot read
- PCIRCLE-AI#525 recall returns an exact name or title match first
- PCIRCLE-AI#566 a session message reminds only the session it is for
- PCIRCLE-AI#511 a plain-name tag for your own project is stored as the project id
- PCIRCLE-AI#408 doctor warns when memories sit under a plain project name
- PCIRCLE-AI#403 message timestamps are ISO 8601 UTC
- PCIRCLE-AI#551 a lesson written with the old type is renamed after the rename
- PCIRCLE-AI#506 hooks stop waiting 30 s for a held database lock
- PCIRCLE-AI#561 an import that adds nothing leaves the memory alone
- PCIRCLE-AI#552 work_package finds a session's recorded directory anywhere in the
  transcript and says which sessions it left out and why
- PCIRCLE-AI#550 import --notes exits 1 when every note is refused
- PCIRCLE-AI#555 doctor reports a hook that keeps failing, counting runs
- PCIRCLE-AI#529 kg backfill-relations previews by default and backs up before --apply
- PCIRCLE-AI#477 release checks no longer fail on environment traps

Where two fixes meet, both are kept: an import compares the redacted text
when it decides nothing was added, and the guard check reports both an
unreadable store and an invalid pattern.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant