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
125 changes: 125 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Testing

This project uses [Bats](https://github.com/bats-core/bats-core) (Bash Automated Testing System) for testing the shell scripts.

## Running Tests

```bash
# Run all tests
bats tests/

# Run specific test file
bats tests/install.bats
bats tests/sync.bats
bats tests/validation.bats

# Run with verbose output (show test names)
bats --tap tests/
```

## Test Structure

```
tests/
├── test_helper.bash # Shared setup/teardown and utilities
├── install.bats # Tests for install.sh
├── sync.bats # Tests for sync.sh commands
└── validation.bats # Tests for skills validation
```

## Writing Tests

### Test File Format

```bash
#!/usr/bin/env bats

load 'test_helper'

setup() {
setup_test_env
}

teardown() {
teardown_test_env
}

@test "description of what this tests" {
# Arrange
create_fake_skill "my-skill"

# Act
run_install

# Assert
assert_symlink "$FAKE_HOME/.claude/skills/my-skill" "$FAKE_REPO/skills/my-skill"
}
```

### Key Conventions

1. **Always use the test environment** - Call `setup_test_env` in setup and `teardown_test_env` in teardown
2. **Use helper functions** - Use `run_install`, `run_sync`, `create_fake_skill`, etc. from test_helper.bash
3. **Test in isolation** - Tests use temp directories (`$FAKE_HOME`, `$FAKE_REPO`) and never touch real config

### Available Test Helpers

**Environment:**
- `setup_test_env` - Creates isolated temp directories
- `teardown_test_env` - Cleans up temp directories
- `$FAKE_HOME` - Temp directory simulating user's home
- `$FAKE_REPO` - Temp directory simulating the repo

**Creating Test Data:**
- `create_fake_skill "name"` - Creates a valid skill with SKILL.md
- `create_invalid_skill "name"` - Creates skill without frontmatter
- `create_skill_no_md "name"` - Creates skill without SKILL.md
- `create_fake_agent "name"` - Creates an agent file
- `create_fake_rule "name"` - Creates a rule file
- `create_fake_settings` - Creates settings.json
- `create_fake_statusline` - Creates statusline.sh

**Running Scripts:**
- `run_install [args]` - Runs install.sh in test environment
- `run_sync [args]` - Runs sync.sh in test environment

**Assertions:**
- `assert_symlink "path" "expected_target"` - Verifies symlink exists and points to target
- `assert_regular_file "path"` - Verifies file exists and is not a symlink
- `assert_dir "path"` - Verifies directory exists
- `assert_backup_exists` - Verifies a backup was created
- `assert_manifest_operation "op"` - Verifies manifest contains operation

**Backup Helpers:**
- `get_latest_backup` - Returns name of most recent backup

### Testing Tips

1. **Test both success and failure cases** - Verify error messages and exit codes
2. **Test dry-run mode** - Ensure `--dry-run` doesn't modify anything
3. **Test idempotency** - Running the same command twice should work
4. **Group related tests** - Use comment headers to organize test sections

## Adding New Tests

When adding new functionality to install.sh or sync.sh:

1. Add tests to the appropriate .bats file
2. Add any new helper functions to test_helper.bash
3. Run `bats tests/` to verify all tests pass
4. Consider edge cases (missing files, conflicts, dry-run)

## CI Integration

Tests run automatically on push/PR via GitHub Actions. See `.github/workflows/test.yml`.

The workflow:
1. Runs on `macos-latest` (matches dev environment)
2. Installs bats-core via Homebrew
3. Runs all tests with `bats tests/`
4. Validates all skills with `./sync.sh validate`

To run locally before pushing:
```bash
bats tests/ && ./sync.sh validate
```
120 changes: 120 additions & 0 deletions .claude/rules/workflows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Workflows

## Setting up on a new machine

```bash
git clone git@github.com:brianlovin/agent-config.git ~/Developer/agent-config
cd ~/Developer/agent-config
./install.sh
```

Creates symlinks from `~/.claude/` to this repo. Local-only items are preserved.

### Dry-run mode

Preview what would happen without making changes:

```bash
./install.sh --dry-run
```

### Handling conflicts

If a local file differs from the repo version, you'll be prompted:
- `[r]` Use repo version (backs up local first)
- `[l]` Keep local version (skip this item)
- `[d]` Show diff between versions
- `[q]` Quit

Use `--force` to automatically use repo versions (still creates backups).

## Sync status legend

```bash
./sync.sh
```

Shows status grouped by type (Skills, Agents, Rules):

- `✓` synced (symlinked to this repo)
- `○` local only (not in repo)
- `⚠` conflict (exists in both - run `./install.sh` to fix)
- `→` external (symlinked elsewhere)

## Adding items to sync across machines

```bash
./sync.sh add skill <name> # Add a skill directory
./sync.sh add agent <name> # Add an agent file (without .md extension)
./sync.sh add rule <name> # Add a rule file (without .md extension)
./sync.sh push
```

Copies the item to repo, replaces local with symlink, prompts for commit.

Skills are validated before adding - must have SKILL.md with `name` and `description` in frontmatter.

## Removing items from repo

```bash
./sync.sh remove skill <name>
./sync.sh remove agent <name>
./sync.sh remove rule <name>
./sync.sh push
```

Removes from repo but keeps local copy.

## Backups and undo

All destructive operations create timestamped backups in `.backup/`.

```bash
./sync.sh backups # List available backups
./sync.sh undo # Restore from last backup
./sync.sh undo --dry-run # Preview what would be restored
```

## Validating skills

Check that all skills have valid SKILL.md files:

```bash
./sync.sh validate
```

Skills must have frontmatter with `name` and `description`:

```yaml
---
name: my-skill
description: What this skill does
---
```

## Dry-run mode

Preview any command without making changes:

```bash
./sync.sh --dry-run add skill my-skill
./sync.sh -n remove agent my-agent
./install.sh --dry-run
```

## Keeping items local-only

Any item in `~/.claude/` that isn't symlinked stays local. The install script only creates symlinks for what's in this repo—it never deletes local files.

Use this for work-specific or experimental items.

## Directory structure

```
~/.claude/
├── skills/ # Skill directories (each has SKILL.md)
├── agents/ # Subagent markdown files
├── rules/ # Rule markdown files
├── settings.json
└── statusline.sh
```
23 changes: 23 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install bats
run: brew install bats-core

- name: Run tests
run: bats tests/

- name: Validate skills
run: ./sync.sh validate
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.backup/
.DS_Store
41 changes: 41 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Agent Config

Personal agent settings, skills, agents, and rules, synced across machines via symlinks.

## Commands

```bash
./install.sh # Set up symlinks (run after cloning)
./install.sh --dry-run # Preview what would be done
./sync.sh # Show sync status
./sync.sh add <type> <name> # Add a local item to repo
./sync.sh remove <type> <name> # Remove item from repo (keeps local)
./sync.sh pull # Pull latest and reinstall symlinks
./sync.sh push # Commit and push changes
./sync.sh undo # Restore from last backup
./sync.sh validate # Validate all skills
./sync.sh backups # List available backups
bats tests/ # Run tests
```

Types: `skill`, `agent`, `rule`

## Testing

Tests use Bats. Run `bats tests/` to execute all tests. Tests run in isolated temp directories.

See [.claude/rules/testing.md](.claude/rules/testing.md) for testing conventions.

## Key Files

- `install.sh` - Creates symlinks from ~/.claude and ~/.codex/skills to this repo
- `sync.sh` - Manages syncing items between local and repo
- `tests/` - Bats test suite

For detailed workflows, see [.claude/rules/workflows.md](.claude/rules/workflows.md).

## Verification

After making changes:
- `bats tests/` - Run all tests
- `./sync.sh validate` - Validate all skills
1 change: 1 addition & 0 deletions CLAUDE.md
Loading