Skip to content

feat: layered, track-aware workspace memorize & retrieve#466

Merged
evan-ak merged 9 commits into
mainfrom
feat/layered-split-tracks
Jul 4, 2026
Merged

feat: layered, track-aware workspace memorize & retrieve#466
evan-ak merged 9 commits into
mainfrom
feat/layered-split-tracks

Conversation

@nevamind-agent

Copy link
Copy Markdown
Contributor

Summary

Reworks the workspace memorize/retrieve pipeline into a layered, track-aware design (ADR 0007). Source resources now synthesize directly into files, files are sliced into embedded segments as the retrieval unit, and both resources and files carry a track tag that scopes retrieval. Built up across four commits:

  1. feat: track resource provenance in workspace memorize — Add an optional track column to Resource recording the workspace subtree a file came from (chat/chat, agent/skill, else workspace). Classified in memorize_workspace and threaded through the workflow as resource_track. Legacy single-file memorize leaves it None. Nullable across all three backends, no migration.

  2. feat: resource → file workspace memorize — Replace the resource → entry → file workspace pipeline (and the generate_skills bypass) with direct resource → file synthesis for chat and skill tracks. Two-step extraction: route the source to the target files, then synthesize each file body in parallel — no RecallEntry created. Adds a RecallFileResource(resource_id, category_id) join table recording resource → file provenance with cascade-delete. Single-file memorize unchanged.

  3. feat: add RecallFileSegment layer for file retrieval — Introduce RecallFileSegment (ADR 0007 L2 item): a searchable slice of a RecallFile carrying text + embedding + recall_file_id, embedded as the retrieval unit that rolls up to its file. Threaded through the full stack (core model, three backends, repos, schemas, file_segments table). Segments are (re)built after file synthesis — one per file for skills, one per content line for memory — with a diff-based drop-and-add so unchanged lines keep their embeddings.

  4. feat: workspace retrieve over segments; denormalize track onto segment — Rework retrieve_workspace to return segments (ranked by embedding, file.top_k), files (roll-up of the files those segments point to, max segment score), and resources (workspace-track resources ranked by embedding, resource.top_k). The entry layer is off. Denormalize track onto RecallFileSegment (mirrored from the owning file at creation, immutable) so segment retrieval filters by track with a plain column predicate instead of a join.

Test plan

  • tests/test_skill_track.py
  • tests/test_folder_memorize.py
  • Verify workspace memorize + retrieve end to end across in-memory, SQLite, and Postgres backends

🤖 Generated with Claude Code

evan-ak and others added 9 commits July 2, 2026 10:55
Add an optional `track` column to the Resource model that records which
workspace subtree a file came from: files under chat/ → "chat", under
agent/ → "skill", everything else → "workspace". Classification happens
in memorize_workspace and threads through the workflow as the
`resource_track` state key. Legacy single-file memorize leaves it None.

The column is nullable across all three backends (in-memory, SQLite,
Postgres), mirroring how RecallFile.track was added — created via
metadata.create_all(), no migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-file `resource → entry → file` workspace pipeline (plus the
`generate_skills` bypass) with a direct `resource → file` synthesis for the
chat and skill tracks:

- Two-step extraction: (a) route the source to the set of files to
  update/create given existing files' names+descriptions, then (b) synthesize
  each target file's body in parallel. No RecallEntry is created on this path.
- Track routing: chat → memory-track RecallFile, skill → skill-track RecallFile,
  workspace → resource-only (no file, no entry).
- Add a RecallFileResource(resource_id, category_id) join table mirroring
  RecallFileEntry across all three backends (inmemory/sqlite/postgres), recording
  resource → file provenance; cascade-delete unlinks it.
- Single-file `memorize` (resource → entry → file) is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce RecallFileSegment (ADR 0007 L2 item): a searchable slice of a
RecallFile carrying text + embedding + recall_file_id. Each file has 1..n
segments, embedded as the retrieval unit that rolls up to its file. No
ordinal — slicing is track-specific and not necessarily sequential.

Threaded through the full stack like RecallFileResource: core model +
inmemory/postgres/sqlite models and schemas (file_segments table),
RecallFileSegmentRepo protocol and three backend repos, DatabaseState,
interfaces, and store wiring.

Segments are (re)built after workspace file synthesis:
- skill track: one "name/description" segment per file
- memory track: one segment per content line, skipping blanks and headings
On update, diff existing vs new segment texts and drop-and-add only the
difference so unchanged lines keep their embeddings. Cleared alongside
categories in the crud clear path.
Rework retrieve_workspace to return segments/files/resources:
- segments: RecallFileSegment ranked by embedding, file.top_k
- files: roll-up of the files those segments point to (max segment score),
  not a ranked search
- resources: workspace-track resources ranked by embedding, resource.top_k
The entry layer is off (config retained but ignored).

Add a denormalized `track` to RecallFileSegment, mirrored from the owning
file at creation, so segment retrieval filters by track with a plain column
predicate instead of a join. Track is immutable (segments are drop-and-recreated
on re-slice), so it never drifts from the file. Threaded through create_segment
across the interface and all three backends; _ws_recall_segments applies
file.tracks as a track__in filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@evan-ak evan-ak merged commit 094e22f into main Jul 4, 2026
3 checks passed
@evan-ak evan-ak deleted the feat/layered-split-tracks branch July 4, 2026 05:42
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.

2 participants