feat(workspace): inject site-agent context into worktrees on creation#46
Merged
Conversation
Adds a default-on injection step to `workspace worktree add` that
snapshots the originating site's agent memory (MEMORY.md, USER.md,
RULES.md) into the new worktree so a fresh agent session cooking in
that worktree starts with the same architectural context its parent
site has accumulated.
Written files:
<worktree>/.claude/CLAUDE.local.md — Claude Code convention
<worktree>/.opencode/AGENTS.local.md — OpenCode convention
Both files receive the same runtime-agnostic payload. The injected
paths are added to the repository's `info/exclude` (NOT .gitignore,
so the tracked repo is never dirtied). git's exclude lookup always
uses the common git dir — per-worktree info/exclude is a no-op — so
we resolve commondir from the worktree's `.git` file and write there.
The patterns are narrow enough to be harmless across other worktrees
and the primary checkout, where no injected files ever exist.
New CLI:
wp datamachine-code workspace worktree add <repo> <branch>
[--skip-context-injection]
wp datamachine-code workspace worktree refresh-context <handle>
New ability:
datamachine/workspace-worktree-refresh-context
Worktree-add ability gains an `inject_context` input (default true);
set false to create a bare worktree. Metadata (`created_from_site`:
URL + agent slug + abspath + timestamp) is persisted in the
`datamachine_worktree_metadata` option keyed by workspace handle, and
dropped when the worktree is removed.
When DM's agent memory layer is unavailable (plugin inactive, running
outside a site context) injection becomes a graceful no-op: the
worktree is still created, the response surfaces
`context_injected=false` with a skip reason, and no error fires.
Closes #45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #45.
Summary
workspace worktree addnow snapshots the originating site's agent memory (MEMORY.md, USER.md, RULES.md) into the new worktree so a fresh agent session starts with the architectural context its parent site has accumulated — not just the repo's auto-loaded files.Two files are written per worktree, both receiving the same runtime-agnostic payload:
The injected paths are added to the repository's
info/exclude(per-checkout ignore, not.gitignore), so the tracked repo is never dirtied andgit statusstays clean.New CLI surface
New ability:
datamachine/workspace-worktree-refresh-context. Theworkspace-worktree-addability gains aninject_contextinput (defaulttrue).Metadata
Per-worktree
created_from_sitemetadata (site URL + agent slug + abspath + ISO timestamp) is persisted in thedatamachine_worktree_metadatasite option keyed by workspace handle, and dropped automatically when the worktree is removed (including path-based removal from cleanup).Graceful degradation
When Data Machine's agent memory layer is unavailable (plugin inactive, running outside a site context), injection becomes a no-op: the worktree is still created, the response surfaces
context_injected=falsewith a skip reason, and no error fires. This matches the spec requirement about invoking outside a site context.Spec deviations / revisions
.git/info/excludesemantics. The issue spec says "Appends both paths to<worktree>/.git/info/exclude" and describes the behavior as "Each worktree manages its own injected context independently." That's not how git exclude resolution works:info/excludeis ALWAYS read from the repository's common git dir ($GIT_COMMON_DIR/info/exclude), never from the per-worktree private gitdir. Writing to<primary>/.git/worktrees/<slug>/info/excludeis a silent no-op — git never reads it. This PR writes to the commoninfo/excludeinstead, and documents the implication: the exclude patterns are visible to every worktree + the primary checkout, but the patterns (.claude/CLAUDE.local.md,.opencode/AGENTS.local.md) only match files we deliberately create in injected worktrees, so there's no behavior change in non-injected checkouts. The "no repo pollution" property still holds (no tracked files touched). The "each worktree independent" property becomes "the exclude pattern list is shared but file presence is still per-worktree."CLI flag name. The spec proposes
--no-inject-context. WP-CLI's synopsis validation rejects declared[--no-<flag>]flags (it normalizes toinject-contextand can't find a match). Switched to--skip-context-injectionto stay within WP-CLI conventions. The ability-level input isinject_context=false(unchanged from spec).Smoke test results
Ran the 8 scenarios from the issue:
workspace worktree addcreates the worktree.claude/CLAUDE.local.md+.opencode/AGENTS.local.mdexist with MEMORY content.git/info/exclude(common dir) contains both pathsgit statusinside worktree shows neither injected filerefresh-context→ injected files reflect new content--skip-context-injection→ neither file written, exclude unchangedbuild_payload()returns null → worktree still created, clean skipFiles
inc/Workspace/WorktreeContextInjector.php— payload builder, renderer, injector, metadata store/forget, common-git-dir resolver.inc/Workspace/Workspace.php—worktree_add()gains$inject_context; newworktree_refresh_context();worktree_remove()and the path-based removal both callforget_metadata().inc/Abilities/WorkspaceAbilities.php—workspace-worktree-addinput schema gainsinject_context; newworkspace-worktree-refresh-contextability.inc/Cli/Commands/WorkspaceCommand.php—--skip-context-injectionflag;refresh-contextsubcommand; contextual output rendering for both.Scope
Deliberately out: cross-machine federation, auto-refresh schedules, selective/differential injection, two-way sync. Matches the issue's "Out of scope" section.