git-tutorial-sandbox

7 stars

Best use case

git-tutorial-sandbox is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Teams using git-tutorial-sandbox should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/git-tutorial-sandbox/SKILL.md --create-dirs "https://raw.githubusercontent.com/heldernoid/agentic-build-templates/main/projects/education-learning/git-tutorial-sandbox/skills/git-tutorial-sandbox/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/git-tutorial-sandbox/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How git-tutorial-sandbox Compares

Feature / Agentgit-tutorial-sandboxStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

This skill provides specific capabilities for your AI agent. See the About section for full details.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Skill: git-tutorial-sandbox

## What this skill knows

This skill covers the git-tutorial-sandbox project: an in-browser interactive Git learning environment powered by isomorphic-git and LightningFS. The agent runs real Git commands in a fake terminal UI against an in-memory filesystem, renders a live commit DAG with D3, and validates lesson steps.

## Tech stack summary

- isomorphic-git v1 for all Git operations
- @isomorphic-git/lightning-fs for the in-browser filesystem (IndexedDB backend)
- React + Zustand for UI and state
- D3-force / D3-DAG for commit graph layout
- React Router v6 for navigation
- Vitest + Testing Library for tests

## isomorphic-git essentials

Every isomorphic-git call needs `fs` (the LightningFS instance) and `dir` (the repo path, always `/repo`).

```ts
import git from 'isomorphic-git';
import { fs } from '@/git/lightningfs';

const DIR = '/repo';

// Init
await git.init({ fs, dir: DIR });

// Stage all
await git.add({ fs, dir: DIR, filepath: '.' });

// Commit
await git.commit({
  fs,
  dir: DIR,
  message: 'Initial commit',
  author: { name: 'Learner', email: 'learner@sandbox.local' },
});

// Log (returns ReadCommitResult[])
const log = await git.log({ fs, dir: DIR });

// Branches
const branches = await git.listBranches({ fs, dir: DIR });
await git.branch({ fs, dir: DIR, ref: 'feature' });
await git.checkout({ fs, dir: DIR, ref: 'feature' });

// Merge
await git.merge({ fs, dir: DIR, theirs: 'feature',
  author: { name: 'Learner', email: 'learner@sandbox.local' } });

// Status matrix
const matrix = await git.statusMatrix({ fs, dir: DIR });
// Each row: [filepath, HEAD, WORKDIR, STAGE]
// 0 = absent, 1 = identical, 2 = modified, 3 = ...
```

## LightningFS singleton

```ts
// src/git/lightningfs.ts
import LightningFS from '@isomorphic-git/lightning-fs';

export const fs = new LightningFS('git-sandbox');

export async function resetFs(): Promise<void> {
  await fs.promises.rm('/repo', { recursive: true }).catch(() => {});
  await fs.promises.mkdir('/repo');
}
```

Import `{ fs }` everywhere. Never create a second LightningFS instance.

## Command parser usage

```ts
import { parseCommand } from '@/git/parser';

const cmd = parseCommand('git branch -d feature');
// => { type: 'branch', name: 'feature', delete: true }

const bad = parseCommand('git blame README.md');
// => { type: 'unknown', raw: 'git blame README.md' }
```

The parser strips leading `git ` before switching on the subcommand.

## useGitCommand hook

```ts
const { runCommand } = useGitCommand();
await runCommand('git commit -m "Add feature"');
// Side effects:
// - Appends prompt + output lines to terminal store
// - Refreshes repo store (commits, branches, HEAD, files)
// - Advances lesson step if command matches expected
```

## Lesson step validation

The expected command in lesson YAML is normalized before comparison:

```ts
function normalize(cmd: string): string {
  return cmd
    .toLowerCase()
    .trim()
    .replace(/\s+/g, ' ')
    .replace(/^git /, '');
}
```

A step advances if `normalize(actual) === normalize(expected)`.

Steps with multiple valid forms use `expectedCommands: string[]` array in the YAML.

## Lesson YAML frontmatter

```yaml
---
id: "03-branching"
title: "Branching Basics"
order: 3
estimatedMinutes: 8
prerequisites: ["01-first-commit", "02-staging"]
steps:
  - id: "create-branch"
    instruction: "Create a new branch called feature."
    expectedCommand: "git branch feature"
    hint: "Use git branch <name> to create a branch without switching."
---
```

## Commit graph derivation

```ts
// src/hooks/useCommitGraph.ts
function deriveGraph(commits: Commit[], branches: Branch[]) {
  const nodes: GraphNode[] = commits.map(c => ({
    id: c.oid,
    shortId: c.shortOid,
    isHead: c.oid === head,
    isMerge: c.parents.length > 1,
    branches: branches.filter(b => b.oid === c.oid).map(b => b.name),
  }));

  const edges: GraphEdge[] = commits.flatMap(c =>
    c.parents.map(parentOid => ({ source: c.oid, target: parentOid }))
  );

  return { nodes, edges };
}
```

## Supported commands

| Command | Parsed as |
|---------|-----------|
| `git init` | `{ type: 'init' }` |
| `git add .` | `{ type: 'add', paths: ['.'] }` |
| `git add README.md auth.js` | `{ type: 'add', paths: ['README.md', 'auth.js'] }` |
| `git commit -m "msg"` | `{ type: 'commit', message: 'msg' }` |
| `git branch feature` | `{ type: 'branch', name: 'feature' }` |
| `git branch -d feature` | `{ type: 'branch', name: 'feature', delete: true }` |
| `git checkout main` | `{ type: 'checkout', ref: 'main' }` |
| `git checkout -b hotfix` | `{ type: 'checkout', ref: 'hotfix', newBranch: true }` |
| `git merge feature` | `{ type: 'merge', branch: 'feature' }` |
| `git log` | `{ type: 'log' }` |
| `git log --oneline` | `{ type: 'log', oneline: true }` |
| `git status` | `{ type: 'status' }` |
| `git diff` | `{ type: 'diff' }` |
| `git diff --staged` | `{ type: 'diff', staged: true }` |
| `git reset --soft HEAD~1` | `{ type: 'reset', mode: 'soft', ref: 'HEAD~1' }` |
| `git reset --hard HEAD` | `{ type: 'reset', mode: 'hard', ref: 'HEAD' }` |
| `git stash` | `{ type: 'stash' }` |
| `git stash pop` | `{ type: 'stash', subcommand: 'pop' }` |
| `git stash list` | `{ type: 'stash', subcommand: 'list' }` |
| `clear` | `{ type: 'clear' }` |
| anything else | `{ type: 'unknown', raw: '...' }` |

## Terminal line kinds

| Kind | Color | When to use |
|------|-------|-------------|
| `prompt` | green | The command the user typed |
| `stdout` | light grey `#d6d3d1` | Normal git output |
| `stderr` | red `#f87171` | Errors, unsupported commands |
| `success` | green `#4ade80` | Step completed confirmation |
| `info` | blue `#93c5fd` | Hints, tips, context |

## localStorage schema

| Key | Type | Contents |
|-----|------|----------|
| `gts_progress` | JSON | `{ [lessonId]: { completedSteps: string[], completedAt?: number } }` |
| `gts_settings` | JSON | terminal font size, hints auto-show, graph visibility |

Progress is saved immediately when each step completes.

## Routes

| Path | Component |
|------|-----------|
| `/` | `HomePage` - lesson card grid |
| `/lesson/:id` | `LessonPage` - 3-column layout |
| `/sandbox` | `SandboxPage` - terminal + graph |
| `/progress` | `ProgressPage` - completion tracker |

## Common mistakes

- Always pass `author` to `git.commit` and `git.merge`. isomorphic-git will throw without it.
- `git.log` returns commits newest first. The DAG renders newest at top.
- `git.statusMatrix` rows: `[filepath, HEAD, WORKDIR, STAGE]`. Values: 0=absent, 1=unchanged, 2=added/modified. Row `[file, 0, 2, 0]` means new untracked file.
- After `git.merge`, call `git.log` to refresh commits - the merge commit OID is not returned by `merge`.
- `git reset` is not a built-in isomorphic-git function. Implement it by calling `git.writeRef` to move HEAD and `git.checkout` or `git.resetIndex` to restore files.

Related Skills

sql-tutorial-engine

7
from heldernoid/agentic-build-templates

No description provided.

Skill: Uptime Monitoring

7
from heldernoid/agentic-build-templates

## Overview

Skill: Status Page

7
from heldernoid/agentic-build-templates

## Overview

Skill: unit-conversion

7
from heldernoid/agentic-build-templates

## Overview

Skill: recipe-scaler

7
from heldernoid/agentic-build-templates

## Overview

reading-list

7
from heldernoid/agentic-build-templates

Operate the reading-list API to save, manage, tag, search, and export articles.

email-digest

7
from heldernoid/agentic-build-templates

Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.

websocket-realtime

7
from heldernoid/agentic-build-templates

Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".

poll-builder

7
from heldernoid/agentic-build-templates

Self-hosted poll creation tool with real-time results. Use when you need to create a poll, check vote counts, close a poll, export results, or get the shareable link for a poll. Triggers include "create poll", "vote", "poll results", "survey", "collect votes", "share poll", or any task involving polling or voting.

Skill: personal-finance

7
from heldernoid/agentic-build-templates

## Overview

Skill: csv-import

7
from heldernoid/agentic-build-templates

## Overview

Skill: Syntax Highlighting

7
from heldernoid/agentic-build-templates

## Purpose