This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A native macOS app (SwiftUI + SwiftData) for discovering, organizing, and editing AI coding agent skills across tools (Claude Code, Cursor, Codex, Windsurf, Copilot, Aider, Amp). Fully open source (MIT), public repo at github.com/Shpigford/chops. No sandbox — requires full filesystem access to read user dotfiles.
# Generate Xcode project (required after changing project.yml)
xcodegen generate
# Open in Xcode
open Chops.xcodeproj
# CLI build
xcodebuild -scheme Chops -configuration Release
# Local release-like build that launches cleanly from shell
xcodebuild -scheme Chops -configuration LocalRelease
# Release (needs APPLE_TEAM_ID, APPLE_ID, SIGNING_IDENTITY_NAME env vars)
./scripts/release.sh <version>Requires: Xcode, brew install xcodegen, macOS 15+. Sparkle (>= 2.6.0) is the only external dependency (auto-updates via GitHub Releases).
No test suite exists. Validate manually by building and running.
Always manually test. After every change, build the app (xcodebuild), launch it, and exercise the feature you changed. Seeing "build succeeded" is not enough — open the app and verify the actual behavior. If it's a UI change, look at it. If it's a data change, confirm the data. No exceptions.
No fallbacks. Do not write fallback logic, graceful degradation, or backwards-compatibility shims. The product should work correctly via the primary code path. If something fails, fix the root cause — don't paper over it with a fallback. We are early-stage; the code should be clean and direct, not defensive.
Entry: Chops/App/ChopsApp.swift → sets up SwiftData ModelContainer + Sparkle updater.
SwiftData store path is explicit: ~/Library/Application Support/Chops/Chops.store. Do not rely on the implicit default.store.
State: AppState is an @Observable singleton holding UI filters, search text, and selection state.
Models (SwiftData):
Skill— a discovered skill file. Uniquely identified by resolved symlink path. Tracks which tools it's installed in.SkillCollection— user-created groupings of skills (pure user data, not filesystem-backed — data loss is permanent).
Schema versioning: SwiftData models use VersionedSchema + SchemaMigrationPlan (see SchemaVersions.swift). Each schema version must declare its own nested @Model snapshots; app code reaches the current version through top-level typealiases like Skill = SchemaV1.Skill. When adding or changing a stored property, freeze the previous schema in place, add a new schema version (e.g. SchemaV2) with its own nested models, move the typealiases to the new version, and add the corresponding MigrationStage. Never point an older schema version at live top-level models — future migrations will crash with duplicate checksums.
Services:
SkillScanner— probes tool directories (~/.claude/skills/, ~/.cursor/rules/, etc.), parses frontmatter, upserts into SwiftData. Deduplicates via resolved symlink paths.FileWatcher— FSEvents viaDispatchSourceFileSystemObject, triggers re-scan on changes.SkillParser→ dispatches toFrontmatterParser(.md) orMDCParser(.mdc).- Agent transports — Chops drives the user's installed
claudeandcodexbinaries directly via a one-shot, request/response pattern. No streaming protocol, no JSON-RPC, no permission gymnastics — Chops sends the system prompt + current file content + user request, the model returns "summary + fenced full file", Chops parses the fence, builds aPendingWrite, and the existing diff-review UI gates the disk write.ClaudeCLIAgent—claude -p --output-format json --system-prompt … --model sonnet --settings '{"effortLevel":"low",…}' "<user message>". Reads the JSON envelope, returnsresult. SeeChops/Services/Agents/Claude/.CodexCLIAgent—codex exec --skip-git-repo-check --sandbox read-only --ephemeral --output-last-message <tmp> "<user message>". Reads the temp file for the final agent message. SeeChops/Services/Agents/Codex/.- Both share
OneShotResponseParser(Chops/Services/Agents/OneShotResponseParser.swift) — the parser tries a structured-edits JSON envelope first and falls back to summary + fenced full-file. Either format produces aPendingWrite. - Both conform to
AgentSession(Chops/Services/Agents/AgentSession.swift);AgentFactory.make(for:)returns the right one.ComposePanelkeys off the protocol so the UI doesn't care which transport is in use.
Views: Three-column NavigationSplitView (Sidebar → List → Detail). Editor uses native NSTextView with markdown highlighting. Cmd+S save via FocusedValues. Agent responses render via MarkdownMessageView (MarkdownUI .gitHub theme + syntax highlighting).
Tool sources are defined in ToolSource.swift — each enum case knows its display name, icon, and filesystem paths to scan.
scripts/release.sh does: xcodegen → archive → export with Developer ID → create DMG → notarize → staple → git tag → generate Sparkle appcast.xml → GitHub Release. Appcast served at chops.md/appcast.xml.
Marketing site lives in site/ — Astro 6, built with npm run build from that directory. Appcast XML is in site/public/appcast.xml.