Skip to main content

VCS Integration Guide

Smithers has first-class support for Git and Jujutsu (jj) version control.

Git Commits

Create commits with the Commit component:
import { Commit } from "smithers/components/Git";

<Commit
  message="feat: Add user authentication"
  all  // Stage all changes
  notes={{ smithers: true, prompt: "Add auth" }}
  onFinished={(result) => {
    console.log(`Committed: ${result.commitHash}`);
  }}
/>

Auto-Generated Messages

Let Claude generate the commit message:
<Commit autoGenerate all />

Selective Commits

Commit specific files:
<Commit
  message="fix: Update config"
  files={["config.json", "settings.ts"]}
/>

Git Notes

Store metadata in git notes:
<Commit
  message="feat: New feature"
  notes={{
    smithers: true,
    executionId: executionId,
    prompt: "Implement the new feature",
    model: "sonnet",
  }}
/>
Read notes:
git notes show HEAD

Code Review

Review changes before committing:
function ReviewAndCommit() {
  const [phase, setPhase] = createSignal("implement");

  return (
    <Ralph maxIterations={5}>
      {phase() === "implement" && (
        <Claude
          allowedTools={["Edit", "Write"]}
          onFinished={() => setPhase("review")}
        >
          Implement the feature.
        </Claude>
      )}

      {phase() === "review" && (
        <Review
          target={{ type: "diff", ref: "main" }}
          criteria={[
            "No security vulnerabilities",
            "Tests included",
          ]}
          onFinished={(review) => {
            if (review.approved) {
              setPhase("commit");
            } else {
              setPhase("implement");
            }
          }}
        />
      )}

      {phase() === "commit" && (
        <Commit
          autoGenerate
          all
          onFinished={() => setPhase("done")}
        />
      )}
    </Ralph>
  );
}

Snapshots (Jujutsu)

For jj users, create snapshots:
// Before risky operations
await db.vcs.logSnapshot({
  snapshotId: await jjSnapshot(),
  description: "Before refactoring",
  timestamp: new Date(),
});

// Perform work...

// Rollback if needed
const snapshots = await db.vcs.getSnapshots(1);
await jjRestore(snapshots[0].snapshotId);

Database Tracking

All VCS operations are logged to the database:
// Log a commit
await db.vcs.logCommit({
  hash: "abc123",
  message: "feat: Add feature",
  author: "claude",
  timestamp: new Date(),
  filesChanged: 5,
  insertions: 100,
  deletions: 20,
  vcsType: "git",
});

// Query commits
const commits = await db.vcs.getCommits(10);

Review Tracking

// Log a review
await db.vcs.logReview({
  reviewId: "r1",
  target: "abc123",
  approved: false,
  summary: "Issues found",
  issues: [
    { severity: "high", file: "auth.ts", description: "..." }
  ],
});

// Get blocking reviews
const blocking = await db.vcs.getBlockingReviews();

Complete Workflow

function FeatureWorkflow() {
  const [phase, setPhase] = createSignal("implement");

  return (
    <SmithersProvider db={db} executionId={executionId}>
      <Orchestration snapshotBeforeStart>
        <Ralph maxIterations={10}>
          {phase() === "implement" && (
            <Phase name="Implementation">
              <Claude
                allowedTools={["Edit", "Write"]}
                onFinished={() => setPhase("test")}
              >
                Implement the feature.
              </Claude>
            </Phase>
          )}

          {phase() === "test" && (
            <Phase name="Testing">
              <Claude
                allowedTools={["Bash"]}
                onFinished={(result) => {
                  if (result.output.includes("PASS")) {
                    setPhase("review");
                  } else {
                    setPhase("implement");
                  }
                }}
              >
                Run the tests.
              </Claude>
            </Phase>
          )}

          {phase() === "review" && (
            <Phase name="Review">
              <Review
                target={{ type: "diff", ref: "main" }}
                criteria={["No security issues", "Tests pass"]}
                onFinished={(review) => {
                  if (review.approved) {
                    setPhase("commit");
                  } else {
                    setPhase("implement");
                  }
                }}
              />
            </Phase>
          )}

          {phase() === "commit" && (
            <Phase name="Commit">
              <Commit
                autoGenerate
                all
                notes={{ smithers: true }}
                onFinished={() => setPhase("done")}
              />
            </Phase>
          )}
        </Ralph>
      </Orchestration>
    </SmithersProvider>
  );
}