Skip to content

feat(agents): implement blit agents sync write path#15

Open
vancura wants to merge 2 commits into
mainfrom
agent-sync
Open

feat(agents): implement blit agents sync write path#15
vancura wants to merge 2 commits into
mainfrom
agent-sync

Conversation

@vancura

@vancura vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Add the full blit agents sync write path alongside the existing --check read mode. Sync regenerates the installed kit's agent files in memory, then applies the 4.10 ownership model: kit-owned files are overwritten when unmodified, shared files (AGENTS.md, CLAUDE.md) have only their managed region rewritten, and user-edited kit-owned files are three-way merged via git merge-file with a <file>.new fallback when git is unavailable or the merge conflicts. The manifest and pristine .blit/base/ copies are refreshed afterward, and --force [path...] restores the kit version on demand.

To regenerate deterministically regardless of environment, the scaffolder now records the scaffold-time template vars in the manifest (BlitManifest.vars), and the adapter generation is ported into a new generate-to-memory module (packages/kit/src/adapters.ts) that stays byte-identical to the scaffolder's adapters. The Cursor adapter config now lists the generated .cursor/hooks/ script in its emits.

Add four sync tests (clean Claude + Cursor parity, --force restore, CLAUDE.md managed-region merge preserving a user note); 15/15 pass.

Overview

This pull request implements the complete "blit agents sync" write path, enabling deterministic regeneration and application of kit-managed agent files with support for the 4.10 ownership model. Previously, the sync feature only supported read-only checking. Now it includes full regeneration logic, conflict resolution for user-edited files, and a --force option to restore kit-owned content on demand.

Key Changes

Manifest Enhancement

BlitManifest now includes a vars: Record<string, string> field that captures template variables at scaffold time. These variables are essential for deterministic regeneration during sync operations, ensuring that regenerated files remain byte-identical to the original scaffold output.

New Adapter Generation Module

A new packages/kit/src/adapters.ts module provides in-memory generation functions for kit adapter files, replacing the need for shell-based generation during sync. This module includes:

  • generateClaudeAdapter() - Produces CLAUDE.md with managed-region markers for content that can be updated without losing user edits outside the marked region
  • generateCursorAdapter() - Generates .cursor/rules/*.mdc files from kit rules and skills
  • collectDocs() and agentsFile() - Handle documentation and agent file collection
  • replaceManagedRegion() - Intelligently updates shared files by only rewriting managed sections, preserving user additions elsewhere

Sync Command Expansion

packages/kit/src/commands/agents.ts now implements the full sync workflow (runFullSync):

  • Regenerates all kit outputs based on stored template variables
  • Overwrites unmodified kit-owned files
  • Applies conflict resolution strategies per file ownership class:
    • Shared files (AGENTS.md, CLAUDE.md): Only the managed region is rewritten, preserving user modifications outside it
    • Kit-owned files: Attempts a git-based three-way merge; if conflicts occur and git is unavailable, falls back to writing a <file>.new file for manual review
  • Removes orphaned manifest entries for files no longer in the regenerated kit
  • Supports --force [path...] option to selectively restore kit versions

Test Coverage

Four new integration tests verify critical sync behaviors:

  • Clean Claude and Cursor projects remain byte-identical after agents sync (and subsequent --check passes)
  • --force properly restores kit-managed content and clears drift
  • User-authored notes outside managed regions (e.g., in CLAUDE.md) are preserved across syncs without counting as drift

Configuration Updates

The Cursor adapter configuration now explicitly lists the generated .cursor/hooks/ script in its emits field, documenting the full set of generated artifacts.

Test Results

All 15 tests pass, including the 4 new sync-specific tests covering clean scaffold parity, force restoration, and managed-region preservation.

Add the full `blit agents sync` write path alongside the existing
`--check` read mode. Sync regenerates the installed kit's agent files
in memory, then applies the 4.10 ownership model: kit-owned files are
overwritten when unmodified, shared files (AGENTS.md, CLAUDE.md) have
only their managed region rewritten, and user-edited kit-owned files
are three-way merged via `git merge-file` with a `<file>.new` fallback
when git is unavailable or the merge conflicts. The manifest and
pristine `.blit/base/` copies are refreshed afterward, and `--force
[path...]` restores the kit version on demand.

To regenerate deterministically regardless of environment, the
scaffolder now records the scaffold-time template vars in the manifest
(BlitManifest.vars), and the adapter generation is ported into a new
generate-to-memory module (packages/kit/src/adapters.ts) that stays
byte-identical to the scaffolder's adapters. The Cursor adapter config
now lists the generated `.cursor/hooks/` script in its emits.

Add four sync tests (clean Claude + Cursor parity, --force restore,
CLAUDE.md managed-region merge preserving a user note); 15/15 pass.

Assisted-by: Claude Opus 4.8
Signed-off-by: Vaclav Vancura <commit@vancura.dev>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@vancura, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 1 hour, 43 minutes, and 38 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7916e789-8d5a-4dcd-be5e-3455d50d8d3d

📥 Commits

Reviewing files that changed from the base of the PR and between 0a7e082 and d589f5d.

📒 Files selected for processing (1)
  • packages/kit/src/commands/agents.ts

Walkthrough

This PR implements deterministic blit agents sync --force regeneration and safe merge for Claude/Cursor agent files. Scaffolding now persists template variables into the manifest; sync uses those variables to regenerate kit outputs in memory and applies them to disk via managed-region or three-way merge strategies tailored by file ownership, with conflict preservation for user review.

Changes

Manifest-driven sync regeneration

Layer / File(s) Summary
Manifest contract extended with template vars
packages/create-blit-tech/src/scaffold.ts
BlitManifest adds a vars: Record<string, string> field; writeBlitManifest accepts and writes template variables into .blit/manifest.json for deterministic later regeneration.
Kit adapter generators for in-memory file production
packages/kit/src/adapters.ts
New module defines GeneratedFile type and export functions (generateClaudeAdapter, generateCursorAdapter, collectDocs) that produce agent adapter outputs from kit content; utilities handle markdown frontmatter stripping, managed-region extraction/replacement, and {{var}} template rendering.
Full sync implementation with merge strategies
packages/kit/src/commands/agents.ts
Exported runFullSync function regenerates kit outputs using stored template vars, compares via SHA hashing, and applies ownership-based merge strategies: shared files use managed-region replacement, kit-owned files use git three-way merge, and conflicts are written as .new for user review. Wiring adds sync --force [path...] CLI support and reports sync outcomes via refreshed manifest and tier-1 summary.
End-to-end sync behavior tests
packages/create-blit-tech/test/scaffold.test.mjs
New test suite with runBlit() helper validates that agents sync on fresh projects preserves byte-identical files, --force restores user-overwritten managed content, and user notes outside managed regions survive sync without drift.
Documentation updates
packages/create-blit-tech/src/index.ts, packages/kit/content/agents.config.json
Header comment documents --ts template flag; Cursor adapter emits config reformatted to multi-line array for readability.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(agents): implement blit agents sync write path' directly and clearly summarizes the main change—adding the full write path for the blit agents sync command.
Docstring Coverage ✅ Passed Docstring coverage is 92.59% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent-sync

Comment @coderabbitai help to get the list of available commands and usage tips.

@vancura

vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@vancura

vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/kit/src/commands/agents.ts`:
- Around line 227-230: regenerate currently computes vars = manifest.vars ??
fallbackVars(root) but never persists those fallbacked values back into the
manifest, so projects without pre-existing vars keep being re-detected on each
sync; update regenerate to assign the resolved vars back to manifest.vars when
manifest.vars was originally undefined (e.g., if (!manifest.vars) manifest.vars
= vars) and ensure the downstream refresh/write logic (the same sync path that
previously only wrote when manifest.vars existed) always writes the updated
manifest so the persisted manifest contains the resolved vars.
- Around line 473-491: The manifest rewrite currently records orphaned paths in
tally.orphaned but never removes them from entryByPath, so stale entries get
written back; before constructing refreshed (and before writeFileSync), remove
those orphaned entries from entryByPath: collect orphaned paths exactly as you
do now (using manifest.files, entry.class === 'user-owned' and
regenerated.has(entry.path')), push them to tally.orphaned, then for each
orphaned path call entryByPath.delete(path) so the subsequent refreshed.files
(built from entryByPath.values()) no longer includes stale entries; keep the
existing logic that preserves manifest.createdAt and manifest.vars when writing
the refreshed manifest.
- Around line 451-462: The code is promoting the user-merged content (merged)
into the kit baseline by calling writeBase(...) and setting entry.sha256 from
merged; instead preserve the refreshed kit/generated content as the new base and
hash instead of the merged result: after a successful gitThreeWayMerge(onDisk,
basePath, incoming) where merged !== null, call writeBase(root, relPath,
incoming) and set entry.sha256 = sha256Text(incoming) (so the
kit-generated/ancestor state remains the baseline). If you still need to record
the user-accepted merge result, add a separate field (e.g., entry.acceptedSha256
= sha256Text(merged)) rather than overwriting the generated baseline; keep
writeRel(root, relPath, merged) and tally.merged.push(relPath) as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 749e3548-ef03-4d3e-b430-13b96a5835aa

📥 Commits

Reviewing files that changed from the base of the PR and between afea44c and 0a7e082.

📒 Files selected for processing (6)
  • packages/create-blit-tech/src/index.ts
  • packages/create-blit-tech/src/scaffold.ts
  • packages/create-blit-tech/test/scaffold.test.mjs
  • packages/kit/content/agents.config.json
  • packages/kit/src/adapters.ts
  • packages/kit/src/commands/agents.ts

Comment thread packages/kit/src/commands/agents.ts
Comment thread packages/kit/src/commands/agents.ts
Comment thread packages/kit/src/commands/agents.ts
…tence

Three fixes to the `blit agents sync` write path:

- Kit-owned clean merges now keep the kit-generated version as the
  base and sha256 baseline instead of the merged result. Recording the
  merged file (which carries the user's edits) as the baseline made the
  next sync treat those edits as the kit default and overwrite them.
- Orphaned manifest entries (files the new kit no longer ships) are now
  removed from the tracked set, so the refreshed manifest stops
  carrying stale entries.
- Resolved fallback template vars are written back onto the manifest
  the first time they are detected, so a project scaffolded before vars
  were tracked stops re-detecting the package manager on every sync.

Assisted-by: Claude Opus 4.8
Signed-off-by: Vaclav Vancura <commit@vancura.dev>
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