Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Agents

These files are shared repo-specific agent skills.

Current shared roles:

- `git-cross-maintainer.md` for safe code changes across Just, Go, and Rust
- `feature-spec-writer.md` for specs and behavior design work
- `safety-reviewer.md` for risky sync, push, patch, remove, and prune changes
- `regression-tester.md` for focused and full regression planning

User-facing docs that mention these roles live in:

- `README.md`
- `docs/overview.md`
- `sbx-kits/README.md`
29 changes: 29 additions & 0 deletions .agents/feature-spec-writer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Feature Spec Writer Skill

## Goal

Write repo-specific specs that are precise enough to implement across all three `git-cross` implementations.

## Required Sections

- User problem.
- Scope and non-goals.
- Functional requirements.
- Safety requirements.
- CLI and UX expectations.
- Test requirements.
- Migration or compatibility notes.

## Repo-Specific Expectations

- State whether the feature affects Just, Go, Rust, or all three.
- Name the commands affected.
- Describe how `Crossfile` and `.cross/metadata.json` must evolve.
- Call out any root-path or delete-path risks.
- Include explicit regression-test expectations.

## Anti-Patterns

- Do not describe only the happy path.
- Do not leave `.crossignore` or root deletion semantics vague.
- Do not assume current implementation behavior is already safe.
31 changes: 31 additions & 0 deletions .agents/git-cross-maintainer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# git-cross Maintainer Skill

## Mission

Make safe, parity-preserving changes to `git-cross`.

## Rules

- Read `AGENTS.md` first.
- Treat `Justfile.cross` as the behavior reference.
- Update Go and Rust when behavior is shared.
- Avoid silent error swallowing.
- Be careful with any `rsync --delete` call.
- Treat `local_path == "."` as a destructive-risk case.
- Never assume repo-root patching is safe under the current implementation.

## Default Work Pattern

1. Inspect current behavior in Just, Go, and Rust.
2. Check the relevant tests.
3. Make the smallest correct shared change.
4. Add or update tests.
5. Verify focused tests, then broader regression coverage.

## High-Risk Areas

- Root path resolution.
- Sparse checkout setup.
- Metadata save/load behavior.
- Remove and prune cleanup logic.
- Sync and push flows that may leak or delete files.
26 changes: 26 additions & 0 deletions .agents/regression-tester.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Regression Tester Skill

## Mission

Define the smallest sufficient regression coverage for `git-cross` behavior changes.

## Rules

- Map the changed command to the existing `test/NNN_*.sh` files first.
- Add focused regression coverage before broadening the suite.
- Treat path handling and sync behavior as high-risk.
- Require parity coverage when behavior changes across implementations.

## Default Verification Order

1. Relevant focused test.
2. `bash test/003_diff.sh` when path resolution or context behavior changed.
3. `bash test/004_sync.sh` when sync/push/delete behavior changed.
4. `bash test/run-all.sh` for larger feature work.

## Required Review Output

- What changed.
- Which tests already cover it.
- Which new tests are required.
- What remains untested.
28 changes: 28 additions & 0 deletions .agents/safety-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Safety Reviewer Skill

## Mission

Review `git-cross` changes for data-loss risk, secret leakage risk, and cross-implementation inconsistency.

## Focus Areas

- `patch`, `sync`, `push`, `remove`, `prune`
- root-path handling
- metadata save/load behavior
- `Crossfile` replay behavior
- any `rsync --delete` usage
- ignore semantics such as `.crossignore`

## Review Questions

1. Can this delete files the user did not intend to delete?
2. Can this copy local-only files into the upstream worktree?
3. Does this behave the same in Just, Go, and Rust?
4. Does failure leave metadata or worktrees in a broken state?
5. Are there explicit tests for the dangerous path?

## Output Style

- Findings first.
- Include file references.
- Prefer concrete safety failures and missing tests over style comments.
9 changes: 9 additions & 0 deletions .claude/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Claude Repo Notes

This folder is for Claude-facing repo guidance.

- Use `.agents/` for durable shared skills.
- Use the files here for Claude-specific quick entrypoints and task framing.
- User-facing docs for the repo workflow live in `README.md` and `docs/`.
- Repo-local sandbox starter kits live in `sbx-kits/`.
- The Claude sandbox starter for this repo lives at `sbx-kits/claude`.
15 changes: 15 additions & 0 deletions .claude/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Claude Commands

## Start Here

- Read `AGENTS.md`.
- Read `context/repo-resources.md`.
- Read `context/root-patching-review.md` when working on overlay or root patching.
- Read `.agents/git-cross-maintainer.md` before editing code.

## When Writing Specs

- Read `.agents/feature-spec-writer.md`.
- Put feature requirements in `specs/<feature>/spec.md`.
- Put implementation constraints in `specs/<feature>/plan.md`.
- Put execution work in `specs/<feature>/tasks.md`.
21 changes: 21 additions & 0 deletions .claude/skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Claude Skill Guidance

## Required Repo Skills

Claude should rely on these repo roles:

- `.agents/git-cross-maintainer.md`
- `.agents/feature-spec-writer.md`
- `.agents/safety-reviewer.md`
- `.agents/regression-tester.md`

## Suggested Usage

- Use `git-cross-maintainer` for code changes.
- Use `feature-spec-writer` before large feature work.
- Use `safety-reviewer` before landing risky path, sync, push, or remove changes.
- Use `regression-tester` before considering behavior work complete.

## Why This Set

This repo's main risk is not syntax complexity. It is behavior safety across three implementations. These four roles cover the core lifecycle without adding too much process.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y fish rsync jq
sudo apt-get install -y fish rsync jq ripgrep
# Install yq
sudo wget --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 5 https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq
sudo chmod +x /usr/bin/yq
Expand All @@ -32,6 +32,7 @@ jobs:
git --version
rsync --version
jq --version
rg --version
yq --version

- name: Run dependency check
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ testdir
# allow
!.github
!.specify
!.claude
!.claude/**
!.agents
!.agents/**
!.opencode
!.opencode/**
!.gitignore
!.goreleaser.yaml

Expand Down
18 changes: 18 additions & 0 deletions .opencode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# OpenCode Repo Skills

This repo keeps canonical shared role guidance in `.agents/` and OpenCode-native skill files in `.opencode/skills/`.

Required skills:

- `git-cross-maintainer`
- `git-cross-spec-writer`
- `git-cross-safety-reviewer`
- `git-cross-regression-tester`

After editing OpenCode skills or config, restart OpenCode so it reloads them.

For sandbox usage, prefer the repo-local starter kit:

- `sbx-kits/opencode`

That keeps the sandbox setup versioned with the repository instead of relying on a user-home path.
13 changes: 13 additions & 0 deletions .opencode/skills/git-cross-maintainer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: git-cross-maintainer
description: Use when changing `git-cross` behavior in `Justfile.cross`, `src-go/main.go`, `src-rust/src/main.rs`, or related tests. Focus on parity, path safety, and minimal correct changes.
---

# git-cross Maintainer

- Read `AGENTS.md` first.
- Treat `Justfile.cross` as the behavior reference.
- Update Go and Rust when the behavior is shared.
- Be careful with `rsync --delete` and any root-path handling.
- Prefer the smallest correct shared change.
- Add or update regression tests before considering behavior work complete.
12 changes: 12 additions & 0 deletions .opencode/skills/git-cross-regression-tester/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: git-cross-regression-tester
description: Use when a `git-cross` behavior change needs test planning or verification, especially for sync, diff, status, patch, push, path resolution, and cross-implementation parity.
---

# git-cross Regression Tester

- Identify the most relevant focused test first.
- Require `test/003_diff.sh` for path or context changes.
- Require `test/004_sync.sh` for sync, push, delete, or ignore-model changes.
- Require broader parity coverage for shared behavior changes.
- Call out what remains untested.
16 changes: 16 additions & 0 deletions .opencode/skills/git-cross-safety-reviewer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: git-cross-safety-reviewer
description: Use when reviewing risky `git-cross` changes involving `patch`, `sync`, `push`, `remove`, `prune`, root paths, `rsync --delete`, metadata, or `.crossignore` semantics.
---

# git-cross Safety Reviewer

Review for:

- data loss risk
- secret leakage risk
- root-path deletion risk
- metadata inconsistency
- parity gaps across Just, Go, and Rust

Report findings first with file references and missing-test notes.
13 changes: 13 additions & 0 deletions .opencode/skills/git-cross-spec-writer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: git-cross-spec-writer
description: Use when writing or revising feature specs for `git-cross`, especially for new commands, new modes, UX changes, root patching, or `.crossignore` behavior.
---

# git-cross Spec Writer

- Capture the user problem before proposing syntax.
- Separate current behavior from proposed behavior.
- Define safety rules explicitly.
- State which commands change.
- State which implementations change.
- Define test requirements and destructive-risk scenarios.
18 changes: 10 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Instructions for AI agents working on this codebase.
| **Just + Fish** | `Justfile.cross` | Fish/Bash | Just | `git` CLI + `jq` | Reference |
| **Rust** (experimental) | `src-rust/src/main.rs` | Rust | Clap | `git2` (minimal) + `duct` | WIP |

Both Go and Rust are single-file implementations (~1500 lines each). Justfile.cross is ~940 lines.
Both Go and Rust are single-file implementations (~1500 lines each). Justfile.cross is ~960 lines.

## File Map

Expand All @@ -21,15 +21,15 @@ Justfile # Root wrapper: delegates `just cross <cmd>` to Justfile.c
Justfile.cross # Shell/Fish reference implementation (all commands)
Crossfile # User-facing state: records use/patch commands for replay
src-go/main.go # Go CLI (single file, Cobra-based)
src-go/go.mod # Go module (go 1.23)
src-go/go.mod # Go module (go 1.24)
src-rust/src/main.rs # Rust CLI (single file, Clap-based)
src-rust/Cargo.toml # Rust dependencies
.git/cross/ # Internal state directory
metadata.json # Patch registry: {patches: [{remote, remote_path, local_path, worktree, branch}]}
worktrees/ # Hidden git worktrees for each patch
test/common.sh # Shared test helpers (setup_sandbox, create_upstream, assertions)
test/run-all.sh # Test runner: discovers and executes test/NNN_*.sh files
test/001-017_*.sh # Individual test files (see coverage matrix below)
test/001-018_*.sh # Individual test files (see coverage matrix below)
```

## Commands (all implementations)
Expand Down Expand Up @@ -67,7 +67,7 @@ test/001-017_*.sh # Individual test files (see coverage matrix below)

| Topic | Just/Fish | Go | Rust |
|-------|-----------|-----|------|
| **Worktree hash** | `md5sum(local_path)` — branch NOT included | `SHA256(remote+path+branch)[:8]` — no field separator | `DefaultHasher(canonical+branch)[:8]` — **non-deterministic across Rust versions** |
| **Worktree hash** | `SHA256(remote\0remote_path\0branch)[:8]` — matches Go | `SHA256(remote+path+branch)[:8]` — no field separator | `DefaultHasher(canonical+branch)[:8]` — **non-deterministic across Rust versions** |
| **Git interface** | Direct `git` CLI everywhere | Mixed: `gogs/git-module` + `os/exec` + `git.Open()` — 3 styles interleaved | `git2` for 2 commands only, `duct`/`run_cmd` for rest — git2 is dead weight |
| **Metadata `id` field** | Written via jq | **Not in struct** — silently dropped on save | Present with `#[serde(default)]` |
| **Crossfile removal** | `grep -v "patch"` — removes ALL lines with "patch" | `strings.Contains(line, "patch") && strings.Contains(line, localPath)` — fragile | Same as Go — fragile substring match |
Expand All @@ -92,7 +92,7 @@ test/001-017_*.sh # Individual test files (see coverage matrix below)

### Test Structure

Tests 001-007 form a chain for Shell/Just (001 is sourced by 002, etc.). Tests 008 (Rust) and 009 (Go) are self-contained monolithic tests. Tests 010-017 are focused feature tests.
Tests 001-007 form a chain for Shell/Just (001 is sourced by 002, etc.). Tests 008 (Rust) and 009 (Go) are self-contained monolithic tests. Tests 010-018 are focused feature tests.

### Coverage Matrix

Expand Down Expand Up @@ -179,7 +179,9 @@ Tests 001-007 form a chain for Shell/Just (001 is sourced by 002, etc.). Tests 0
- Tests 008/009 are self-contained and build their own binaries.
- To run a specific test: `bash test/NNN_name.sh`.
- To run all: `bash test/run-all.sh` or `just cross-test`.
- CI runs on `ubuntu-latest` and does NOT install Go/Rust toolchains — tests 008/009 must handle this gracefully (skip with message).
- CI runs on `ubuntu-latest` and does NOT install Go/Rust toolchains — tests 008/009/011 must handle this gracefully (skip with message if build fails).
- Go binary builds must remove stale `src-go/vendor/` before building and pass `-mod=mod` directly as a flag (not via `GOFLAGS`). The vendor directory is gitignored but may exist locally.
- Rust tests must handle `cargo build` failures gracefully — skip instead of failing the test.

### Commit Conventions

Expand All @@ -191,10 +193,10 @@ Tests 001-007 form a chain for Shell/Just (001 is sourced by 002, etc.). Tests 0
## Implementation Details

- **Hidden worktrees**: `.git/cross/worktrees/<remote>_<hash>`.
- **Sparse checkout**: `git sparse-checkout set <path>` — only specified paths checked out.
- **Sparse checkout**: `git sparse-checkout init --no-cone` + `git sparse-checkout set <path>/` + `git read-tree -mu HEAD`. The trailing `/` on the pattern is required for reliable directory matching in `--no-cone` mode on newer Git versions (2.43+). `read-tree -mu HEAD` explicitly materializes the worktree (bare `git checkout` can no-op after `--no-checkout`).
- **Rsync**: `rsync -av --delete --exclude .git` for worktree-to-local sync. `--delete` removes files locally that were deleted upstream.
- **Crossfile format**: Lines like `cross use <name> <url>` or `cross patch <remote>:<branch>:<path> <local>`. Parsed as bash during `replay`.
- **Metadata format**: JSON at `.git/cross/metadata.json`. Schema: `{"patches": [{"id", "remote", "remote_path", "local_path", "worktree", "branch"}]}`.
- **.crossignore**: Located in the root of each local_path, uses gitignore-style patterns to exclude files from status and diff comparisons. Implemented by filtering directory trees using git add and git clean to remove ignored files before comparison.

## Refactoring Priorities

Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- **User documentation refresh** - Added a clearer top-level README, a user-facing architecture overview, and a tutorial for local overlays, publishing to your own origin, and sending changes back upstream.
- **Repo-local `sbx` starter kit** - Added `sbx-kits/opencode` plus `sbx-kits/README.md` so users can try `git-cross` in a versioned sandbox setup instead of relying on a home-directory kit path.
- **AI skill documentation pointers** - Expanded the repo docs to point users and agent tools at `.agents/`, `.claude/`, and `.opencode/skills/`.
- **Whole-upstream tutorial** - Added a second tutorial showing how to vendor an entire upstream repository into a local directory with `remote:.` or `remote:/`.
- **Claude sandbox starter** - Added `sbx-kits/claude` so repo-local sandbox examples now cover both OpenCode and Claude.
- **Private fork migration tutorial** - Added a guarded tutorial for migrating an existing private fork or derivative repo to a repo-root `git-cross` patch with explicit backup and override review steps.

### Changed
- **`.crossignore` entry syntax** - Override review behavior now uses plain non-comment `.crossignore` lines such as `.env` or `config/private` instead of `!override <path>` markers. Wildcard pattern matching is still not supported.
- **README workflow guidance** - Documented the current `.crossignore` behavior as a review-oriented workflow for local overlay files layered on top of upstream-managed content.

### Fixed
- **Rust override diff build failure** - Renamed a Rust loop variable that used the reserved keyword `override`, restoring Rust CLI builds and regression execution on current toolchains.
- **Just override warning output** - Removed a shell-breaking semicolon from the override review warning so `just cross diff` prints the manual review commands correctly.
- **P0: Sparse checkout broken on newer Git versions** - `git sparse-checkout set <path>` in `--no-cone` mode no longer reliably checks out directories without trailing `/`. Fixed across all three implementations (Go, Rust, Justfile.cross) by appending `/` to sparse-checkout patterns and using `git read-tree -mu HEAD` instead of bare `git checkout` (which can no-op after `--no-checkout`).
- **P0: Go build "inconsistent vendoring" in CI** - Tests that build the Go binary now remove stale `vendor/` directory and pass `-mod=mod` as a direct flag. Added `src-go/vendor/` to `.gitignore` to prevent accidental commits.
- **Whole-repo patching (`:/` and `:.`)** - `cross patch remote:/` and `cross patch remote:.` now correctly patch the entire upstream repo. Previously `/` was rejected as invalid, and `.` produced an empty worktree because sparse-checkout pattern `./` matched nothing. Fix: `/` is normalized to `.`, and `.` skips sparse-checkout entirely (full checkout).
- **Prune leaves orphaned `.cross/worktrees/` directories** - `cross prune` now scans `.cross/worktrees/` and removes directories not referenced in `metadata.json`. Previously only `git worktree prune` was called, which cleans git's internal registry but not the actual cross-managed directories.
- **test/014_remove.sh robustness** - Go binary is now reused if already built; gracefully skips Go tests when Go toolchain is unavailable.

### Added
Expand Down
Loading
Loading