Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
176 commits
Select commit Hold shift + click to select a range
9d9dfc2
Merge pull request #28 from whmoro/main
mswdev Apr 27, 2026
0b365b4
Add Ckipper multi-account design doc
mswdev Apr 27, 2026
4b5a15f
Add Ckipper multi-account implementation plan
mswdev Apr 27, 2026
f6a4260
Apply panel review revisions to Ckipper design and plan
mswdev Apr 27, 2026
0750967
Pre-execute polish: prerequisites, Phase 7 user-driven note, doc nit
mswdev Apr 27, 2026
13b61b0
Rename project to Ckipper in CLAUDE.md
mswdev Apr 27, 2026
3f92281
Rename project to Ckipper in README
mswdev Apr 27, 2026
a109ff5
Rename Docker image tag claude-dev -> ckipper-dev
mswdev Apr 27, 2026
c5b0ef8
Deploy Ckipper tooling to ~/.ckipper/ and split settings template
mswdev Apr 27, 2026
114ba9f
Source w-function from ~/.ckipper/ instead of ~/.claude/docker/
mswdev Apr 27, 2026
19b84a8
install.sh: migrate legacy ~/.claude/docker/ to ~/.ckipper/
mswdev Apr 27, 2026
4d75bee
Add ckipper CLI scaffold with per-subcommand help
mswdev Apr 27, 2026
49771d1
Implement ckipper list
mswdev Apr 27, 2026
ed298b0
Implement ckipper add: validated keychain shape, atomic registry, fix…
mswdev Apr 27, 2026
c3c70fd
ckipper: testable OSTYPE override and registry-local temp file
mswdev Apr 27, 2026
5183afe
Implement ckipper default and remove with quote safety
mswdev Apr 27, 2026
56c5792
Auto-generate self-contained aliases.zsh with cca dispatcher
mswdev Apr 27, 2026
276ca2d
Implement ckipper sync-hooks; document template seed-only stance
mswdev Apr 27, 2026
81cc64d
w: resolve active account from --account, env, or registered default
mswdev Apr 27, 2026
241a331
w: thread active account through Docker; extract registry-driven cleanup
mswdev Apr 27, 2026
4c4469a
entrypoint: read all Claude paths from CLAUDE_CONFIG_DIR; error if unset
mswdev Apr 27, 2026
91ce152
hooks: extend protection to per-account dirs and ~/.ckipper
mswdev Apr 27, 2026
d2c6a60
Implement ckipper migrate: precondition checks, error-trap rollback, …
mswdev Apr 27, 2026
cb5730f
README: rewrite for Ckipper with multi-account walkthrough and warnings
mswdev Apr 27, 2026
f91bc74
Docs: CLAUDE.md and test-prompt.md updates with concrete Section 12 i…
mswdev Apr 27, 2026
a640997
Drop .claude-host.json staging mount (incompatible with macOS Docker …
mswdev Apr 27, 2026
8f4f66b
install.sh: legacy migration writes to $CKIPPER_DIR/docker/, not the …
mswdev Apr 28, 2026
291da3d
install.sh: rewrite full source line in .zshrc, not just the path
mswdev Apr 28, 2026
5cef1de
Remove docs/plans/ — implementation plan artifacts, not for the repo
mswdev Apr 28, 2026
0c70f96
aliases.zsh: guard bare 'claude' from clobbering default account creds
mswdev Apr 28, 2026
7418d30
Pre-flight review fixes (3 blockers + 3 should-fix)
mswdev Apr 28, 2026
e38e4a8
Ultrareview fixes: 3 verified bugs in PR #29
mswdev Apr 28, 2026
b06c6ae
Major UX/correctness fixes from real-world Phase 7 use
mswdev Apr 29, 2026
8a96e9d
Add ckipper sync, ckipper doctor, README multi-account caveats
mswdev Apr 29, 2026
af2dbe9
Bug bash from think-tank audit: 12 verified bugs fixed + ck alias
mswdev Apr 29, 2026
f850192
Simplify launchers: drop cca, add bare-name shortcuts, friendlier lis…
mswdev Apr 29, 2026
5ce5c77
ckipper add: deploy hooks before /login; friendlier lock-wait UX
mswdev Apr 29, 2026
2171534
ckipper: rewrite plugin metadata paths on migrate; add repair-plugins…
mswdev Apr 29, 2026
4f61b50
Merge pull request #29 from whmoro/feature/ckipper-multi-account
mswdev Apr 29, 2026
fc7fa76
Adopt llm-agent-kit: .claude/ rules + AGENTS.md
mswdev Apr 29, 2026
8a48b00
Merge pull request #30 from whmoro/feature/agent-kit-import
mswdev Apr 29, 2026
bebfa77
Phase 0: author CLAUDE.md, fill Linting section, add shell-conventions
mswdev Apr 29, 2026
c399549
Phase 1: foundation (lint, test, CI scaffolding) + apply shfmt baseline
mswdev Apr 29, 2026
f855a65
Phase 1.5: characterization tests for ckipper subcommands and w()
mswdev Apr 29, 2026
1e7bed2
Phase 2: modularize ckipper.zsh into lib/core/ + lib/ckipper/
mswdev Apr 29, 2026
51536b6
Phase 3: modularize w-function.zsh into lib/w/
mswdev Apr 29, 2026
a15ce17
Phase 2.5: install.sh deploys lib/ tree (excludes test files)
mswdev Apr 29, 2026
7bb60fa
Phase 4 (Track C): Python refactor + hooks fail-closed + entrypoint/f…
mswdev Apr 29, 2026
1a2e6b4
Phase 4 (Track B): refactor lib/w/ — caps, constants, naming, MED sec…
mswdev Apr 29, 2026
2210d2d
fix(entrypoint): use export-only to avoid readonly variable assignmen…
mswdev Apr 29, 2026
1ee43ad
Phase 4 (Track B): fix jq JSON validation and zsh nameref compatibility
mswdev Apr 29, 2026
3add104
Phase 4 (Track A): refactor lib/core/ + lib/ckipper/ — caps, constant…
mswdev Apr 29, 2026
0781000
Phase 4 (Track A fix): bring _ckipper_doctor and _ckipper_migrate_run…
mswdev Apr 29, 2026
1dff1b5
Phase 4: document zsh completion _w() as exempt from 25-line cap (DSL…
mswdev Apr 29, 2026
745d32b
Phase 5 (Track C): pytest for cleanup-projects + install.sh integrati…
mswdev Apr 29, 2026
6405398
Phase 5 (Track B): bats tests for lib/ckipper/
mswdev Apr 29, 2026
3b6268a
Phase 5 (Track D): doc-headers gap-fill + public-release files
mswdev Apr 29, 2026
e29d69d
Phase 5 (Track A): bats tests for lib/core/, lib/w/, and hooks/
mswdev Apr 29, 2026
f2d06dc
Phase 5 (Track B): expand ckipper module tests to cover all focus areas
mswdev Apr 29, 2026
37a8a6a
Code review fixes: SECURITY.md repo URL + replace eval with stdout pa…
mswdev Apr 29, 2026
53ce593
Fix SECURITY.md: correct repo URL (whmoro/ckipper -> whmoro/claude-do…
mswdev Apr 29, 2026
ceaac13
Code review: bring all lib/ckipper/ functions under 3-param cap (use …
mswdev Apr 29, 2026
2abf891
Code review: standardize boolean locals on "true"/"false" strings (pe…
mswdev Apr 29, 2026
92601ce
Trim rules + fix README staleness
mswdev Apr 30, 2026
e20d0d7
Update repo URLs after GitHub rename to Ckipper
mswdev Apr 30, 2026
3f55d6c
Update repo URLs after ownership transfer to mswdev
mswdev Apr 30, 2026
54a6184
Code review (C1): fix stdout pollution in migrate interactive helpers
mswdev Apr 30, 2026
1d304be
Code review (S1-S5): close remaining rule deviations from PR description
mswdev Apr 30, 2026
d026f22
Trim README + add post-merge upgrade flow
mswdev Apr 30, 2026
0f80e57
Merge pull request #31 from mswdev/feature/rules-compliance-refactor
mswdev Apr 30, 2026
a0e2796
Reorganize root files and make project/worktree dirs user-configurable
mswdev Apr 30, 2026
db91fcb
Code review (S1): refresh _w_reset_globals doc-header
mswdev Apr 30, 2026
431ea72
Code review (I1): move projects/worktrees dir defaults out of _w_rese…
mswdev Apr 30, 2026
fb540ba
Code review (S2): add bats test guarding completion version sentinel …
mswdev Apr 30, 2026
2af48d6
Merge pull request #32 from mswdev/feature/reorganize-and-paths
mswdev Apr 30, 2026
8fc37e0
Add _core_fuzzy_suggest helper for unknown-command suggestions
mswdev Apr 30, 2026
03331e3
Drop ckipper migrate (legacy claude-docker-sandbox migration)
mswdev Apr 30, 2026
46554c0
Rename lib/ckipper/ to lib/account/
mswdev Apr 30, 2026
71610a1
Rename _ckipper_* (account ops) to _ckipper_account_*
mswdev Apr 30, 2026
0e0e7a8
Rename lib/w/ to lib/worktree/ and _w_* to _ckipper_worktree_*
mswdev Apr 30, 2026
9487573
Rename W_* globals to CKIPPER_* (config) and CKIPPER_WT_* (runtime)
mswdev Apr 30, 2026
f0e713f
Restructure worktree arg parsing: drop mode dispatch, split run/rm pa…
mswdev Apr 30, 2026
0f78e2d
Add namespace dispatchers (account, worktree) with help and fuzzy-sug…
mswdev Apr 30, 2026
922519b
Rewrite top-level ckipper() dispatcher: namespaces + short aliases + …
mswdev Apr 30, 2026
a93c4f7
Merge w-function.zsh into ckipper.zsh as single entry script
mswdev Apr 30, 2026
bda83fa
Rename w-config.zsh template + ckipper.zsh entry script paths
mswdev Apr 30, 2026
2e744de
install.sh: rewrite zshrc to ckipper.zsh, delete stale w-function/w-c…
mswdev Apr 30, 2026
973dc7e
Doctor + per-subcommand help text: update user-facing strings to name…
mswdev Apr 30, 2026
0381259
Update README, CHANGELOG, CLAUDE.md, shell-conventions, CONTRIBUTING …
mswdev Apr 30, 2026
d0785c2
docs: update CONTRIBUTING and README layout table to lib/account, lib…
mswdev Apr 30, 2026
9509869
Add make lint-merge-guards: catch _w_/W_ leakage and cross-namespace …
mswdev Apr 30, 2026
05dd0e9
Address PR #33 review: namespace stale strings + shrink worktree disp…
mswdev Apr 30, 2026
e06440f
Address validated 3-agent review: critical install fixes + tech-debt …
mswdev Apr 30, 2026
d034fe4
Merge pull request #33 from mswdev/feature/merge-w-into-ckipper
mswdev Apr 30, 2026
3c4511e
Scrub personally identifying info from public-facing docs
mswdev May 1, 2026
5829b3a
docs: add vibe-engineered disclaimer at top of README
mswdev May 1, 2026
abdb18d
Public-release hardening sweep (audit follow-up)
mswdev May 1, 2026
1ca7c25
Merge pull request #34 from mswdev/feature/audit-paths-and-personal-refs
mswdev May 1, 2026
977c30c
chore: add gum to make bootstrap
mswdev May 1, 2026
61ac967
feat: declare ckipper config schema (lib/config/schema.zsh)
mswdev May 1, 2026
26eb16a
feat: add core config get/set/unset/validate primitives
mswdev May 1, 2026
c9b9a70
fix: read_account distinguishes false from missing in jq lookup
mswdev May 1, 2026
34dab9a
test: cover int_array/string/path validate, set-no-account, account u…
mswdev May 1, 2026
ccc567a
feat: add ckipper config namespace (get/set/unset/list/edit)
mswdev May 1, 2026
6b6f607
fix: harden ckipper config — validate account, fix $path clobber, add…
mswdev May 1, 2026
2bc6d75
refactor: inline _ckipper_config_set absorb-positional helper
mswdev May 1, 2026
65100f8
feat: wire ckipper config namespace into top-level dispatcher
mswdev May 1, 2026
16e0190
feat: auto-migrate accounts.json v1 -> v2 with per-account preferences
mswdev May 1, 2026
9091790
fix: account add records v2 preferences with safe defaults
mswdev May 1, 2026
8bbcbaf
feat: add lib/core/style.zsh ANSI helpers
mswdev May 1, 2026
7cdfc21
feat: add lib/core/help.zsh uniform help renderer
mswdev May 1, 2026
0c58816
feat: add lib/core/prompt.zsh gum + fallback wrappers
mswdev May 1, 2026
9eec54c
fix: wire phase 2 modules into ckipper.zsh + align _core_prompt_input…
mswdev May 1, 2026
26929e7
feat: add lib/setup/prereqs.zsh — wizard prereq checks
mswdev May 1, 2026
606bea8
feat: add lib/setup/prompts.zsh — wizard default-and-tweak flow
mswdev May 1, 2026
5a61de1
feat: add lib/setup/apply.zsh — write wizard updates to config + regi…
mswdev May 1, 2026
ded2ba8
feat: add ckipper setup wizard
mswdev May 1, 2026
e7c056f
feat: auto-detect origin/HEAD as base branch + use CKIPPER_DEP_INSTAL…
mswdev May 1, 2026
6d44af5
feat: per-account always_docker/always_firewall/ssh_forward with --no…
mswdev May 1, 2026
d2d3a4d
feat: add ck run shortcut + bare ck interactive launcher
mswdev May 1, 2026
69edac7
feat: gum-driven cleanup for ckipper account remove
mswdev May 1, 2026
c0d9b1b
feat: doctor --fix absorbs repair-plugins; hide sync-hooks from publi…
mswdev May 1, 2026
07dd3a2
refactor: restyle list/doctor output + render all help via _core_help…
mswdev May 1, 2026
436ed04
feat: install.sh requires gum + auto-invokes ckipper setup
mswdev May 1, 2026
0f3d04d
feat: doctor validates accounts.json v2 preferences + ckipper-config.…
mswdev May 1, 2026
99ec631
docs: rewrite for CLI + onboarding overhaul
mswdev May 1, 2026
b88c7e7
chore: extend lint-merge-guards for setup/config/run/launcher prefixes
mswdev May 1, 2026
8af21c5
docs: collapse duplicate Unreleased heading in CHANGELOG
mswdev May 1, 2026
d97df28
fix: address PR review findings on config namespace + migration coverage
mswdev May 2, 2026
15ca54b
fix: PR #36 review — config security, locking, and schema validation
mswdev May 2, 2026
7164714
refactor: PR #36 review — extract SSH mounts helper, precheck brew
mswdev May 2, 2026
ca428d2
docs: PR #36 review — clarify orchestration-vs-feature dispatcher exc…
mswdev May 2, 2026
ba8aab5
fix: PR #36 review — account remove help text + orphan doc-header
mswdev May 2, 2026
356360c
ci: install gum in CI workflow
mswdev May 2, 2026
238bd04
Merge pull request #36 from mswdev/feature/cli-onboarding-overhaul
mswdev May 2, 2026
7706f9c
feat(sync): registry + engine/dispatcher skeletons (Phase 1)
mswdev May 2, 2026
d4dab31
feat(sync): backup primitives (Phase 2)
mswdev May 2, 2026
b2f538d
feat(sync): structured strategies — mcp/settings/prefs (Phase 3)
mswdev May 2, 2026
c3e3223
feat(sync): files-based strategies (Phase 4)
mswdev May 2, 2026
2b346ad
feat(sync): special strategies — statusline + hooks (Phase 5)
mswdev May 2, 2026
54aa19d
feat(sync): engine core (Phase 6)
mswdev May 2, 2026
086d52d
feat(sync): preview UX — summary table + drill-down picker (Phase 7)
mswdev May 2, 2026
4d46b5a
feat(sync): interactive wizard — gum pickers (Phase 8)
mswdev May 2, 2026
ea61ee6
feat(sync): wire dispatcher end-to-end + remove old monolith (Phase 9)
mswdev May 2, 2026
765d824
refactor(account): rename sync-hooks → redeploy-hooks (Phase 10)
mswdev May 2, 2026
5c641ed
feat(setup): offer initial sync after adding 2nd-or-later account (Ph…
mswdev May 2, 2026
f1c5b09
docs(sync): docs sweep + tab completion bump (Phase 12)
mswdev May 2, 2026
7df8a43
fix(sync): code-review feedback (PR #37)
mswdev May 2, 2026
0c3724f
fix(sync): second-round code-review feedback (PR #37)
mswdev May 3, 2026
2c296d1
fix(sync): third-round code-review feedback (PR #37)
mswdev May 3, 2026
56f2837
fix(sync): fourth-round code-review bug fixes (PR #37)
mswdev May 3, 2026
8adf336
refactor(sync): /simplify pass — extract _shared.zsh, dedup helpers (…
mswdev May 3, 2026
ea2427c
fix(sync): fifth-round code-review bug fixes (PR #37)
mswdev May 3, 2026
3086a2c
Merge pull request #37 from mswdev/feature/sync-overhaul
mswdev May 4, 2026
60a5b72
fix(account): print errors and usage to stderr; modernize keychain pi…
mswdev May 4, 2026
9894aaf
refactor: standardize prompt helpers and module-constant prefixes
mswdev May 4, 2026
872ccb3
feat: doctor checks, config-key completion, fuller setup summary
mswdev May 4, 2026
0199490
docs(readme): clarify Docker-mode limitations + slogan/table updates
mswdev May 4, 2026
dc6d8e6
Merge pull request #38 from mswdev/feature/cohesion-and-doc-cleanup
mswdev May 4, 2026
e38c6e4
fix(core/registry): hold lockdir for full critical section
mswdev May 4, 2026
35715e0
fix(core/config): write int_array values as zsh array literals
mswdev May 4, 2026
71a4ce9
fix(account): switch keychain picker to stdout-capture (zsh has no na…
mswdev May 4, 2026
fd54243
fix(account): refuse to remove an account while Claude is running
mswdev May 4, 2026
0889f40
fix(account): surface registry-write failures in default and remove
mswdev May 4, 2026
235bca8
fix(sync/settings): use JSON path arrays so hyphen/dot keys round-trip
mswdev May 4, 2026
b53ff8c
fix(hooks): close rm -r bypass and stop self-blocking --force-with-lease
mswdev May 4, 2026
2e00045
refactor(core): move schema.zsh into lib/core/
mswdev May 4, 2026
315f39f
refactor(sync): consolidate _CKIPPER_SYNC_CTX declaration into _share…
mswdev May 4, 2026
a2735fc
refactor(core): namespace bare module constants with _CORE_ prefix
mswdev May 4, 2026
06a312a
refactor(worktree): namespace bare module constants with _CKIPPER_WT_…
mswdev May 4, 2026
1b096fc
refactor(worktree): standardize boolean style and convert unquoted fi…
mswdev May 4, 2026
01e9c30
fix(config): honor --help short-circuit on every subcommand
mswdev May 4, 2026
9bb2986
fix(hooks): unify .git path-protection regex between Bash and Edit/Write
mswdev May 4, 2026
c535ca7
chore(ci): add minimal token permissions and a job timeout
mswdev May 4, 2026
f5a8ac3
fix: phase-3 polish — param cap, stderr discipline, unguarded cd
mswdev May 4, 2026
dd797ca
Merge pull request #39 from mswdev/feature/develop-review-fixes
mswdev May 4, 2026
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
106 changes: 106 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# CLAUDE.md

See @README.md for project overview.

> **Product:** Ckipper — multi-account Claude Code manager with Docker isolation.
> **Repo:** Single-package zsh project. Top-level layout in §1.

## Quick Reference

**Core Rules:**
- @.claude/rules/code-style.md — Naming, complexity limits, documentation
- @.claude/rules/testing.md — Test structure, what to test, quality gates
- @.claude/rules/security.md — Security requirements
- @.claude/rules/file-organization.md — Directory structure, file caps, dependency direction

**Package Rules:** *(add package-specific rule files as needed)*
<!-- Example:
- @.claude/rules/backend/api.md — API layer rules
- @.claude/rules/frontend/webapp.md — Frontend rules
-->

## How to Use These Instructions

1. **Always follow** the core philosophy and code standards
2. **Consult package-specific rules** when working in individual packages
3. **Package rules extend, not override** shared standards (e.g., a backend package adds validation requirements but doesn't remove the 25-line method limit)

## 1. Project Overview

Ckipper is a zsh-based wrapper for the [Claude Code CLI](https://claude.ai/cli) that provides:

- **Multi-account isolation** — separate `~/.claude-<account>/` config dirs per registered account, with macOS Keychain integration for credentials.
- **Worktree-aware launchers** — `w <project> <branch>` creates a git worktree, syncs settings, and either runs Claude Code locally or launches it inside a hardened Docker container.
- **Per-account aliases** — auto-generated `<account>` shell functions (e.g., `personal`, `work`) that route to the correct config dir.
- **Safety hooks** — Claude Code hooks (`bash-guardrails.sh`, `protect-claude-config.sh`) that block destructive commands and protect Ckipper-owned config files from accidental modification.
- **Docker sandbox** — Dockerfile + entrypoint that isolate Claude Code with an egress firewall, credential injection via tmpfs, and pre-installed MCP server tooling.

**Top-level layout:**

```
ckipper.zsh # ckipper CLI entry (sourced from .zshrc)
lib/core/ # shared primitives (registry, keychain, config, prompt, style)
lib/account/ # ckipper account subcommands (feature dir)
lib/worktree/ # ckipper worktree subcommands (feature dir)
lib/config/ # ckipper config get/set/unset/list/edit (feature dir)
lib/setup/ # ckipper setup wizard (orchestration: delegates to features)
lib/run/ # ckipper run shortcut for `worktree run` (orchestration)
lib/launcher/ # bare `ck` interactive menu (orchestration)
hooks/ # Claude Code safety hooks
docker/ # Dockerfile + entrypoint + firewall + cleanup
tests/ # bats + pytest tests
install.sh # one-shot installer (copies to ~/.ckipper/)
.claude/ # rules + project Claude config
```

`lib/` has two layers (per `.claude/rules/shell-conventions.md`): feature dirs own subcommand functionality and MUST NOT call into each other; orchestration dirs delegate to feature dirs' public entry points.

## 2. Core Engineering Philosophy

1. **KISS** — Keep It Simple, Stupid. The simplest solution that works is the best solution.
2. **Clarity over cleverness** — No tricks, no golf, no "elegant" one-liners that require a comment to explain.
3. **Functional decomposition** — Break problems into small, named, single-purpose functions.
4. **Object-Oriented Design** — Model the domain with clear objects, well-defined boundaries, and explicit contracts.
5. **Test what matters** — Unit tests are not optional. If logic makes a decision, it gets a test. ALWAYS WRITE TESTS.
6. **SOLID Principles** — Follow SOLID programming principles.

## 3. Code Review Checklist

Before approving any PR, verify:
- [ ] **Can I understand every method without reading its callees?** If no, the names need work.
- [ ] **There are NO MAGIC NUMBERS**
- [ ] **Is every method <= 25 lines?** NO EXCEPTIONS.
- [ ] **Is nesting <= 2 levels deep?** Extract if not.
- [ ] **Does each module/class have a single, obvious responsibility?**
- [ ] **Are there tests for every decision point in the logic?**
- [ ] **Is there any cleverness that should be replaced with clarity?**
- [ ] **Would a new teammate understand this in 5 minutes?**
- [ ] **Do new entry points (CLI, scripts, API endpoints) validate input at trust boundaries?**
- [ ] **Do exported functions have clear documentation when behavior isn't obvious from name and signature?**
- [ ] **Do route handlers and service methods log their outcomes (success, not-found, error)?**
- [ ] **Do error paths surface to monitoring — never swallowed silently?**

## 4. Infrastructure & Services

CI runs `make lint` + `make test-unit` on `macos-latest` via `.github/workflows/ci.yml`.

## 5. Git Workflow

**Branch naming:** `feature/{ticket-or-slug}-{short-description}` (e.g., `feature/123-user-auth`)
**Commit messages:** Reference the ticket if applicable (e.g., `#123: Implement user auth flow`)
**Always use feature branches + PRs.** NEVER commit directly to `main` or `develop`.
**ALWAYS create PRs as drafts** (`gh pr create --draft`). The author decides when to mark "Ready for review."
**PR description:** Link to the ticket if applicable, describe what changed and why, list affected files.

## 6. AI-Specific Instructions

- **Read and ingest before you edit.** Always read relevant source files before proposing changes. NEVER speculate about code you haven't inspected.
- **These rules are authoritative over observed codebase patterns.** If existing code violates a rule in this document or `.claude/rules/`, that is technical debt — not a convention to follow. Never justify bad practices because you see them elsewhere in the repo. When in doubt, follow the rules, not the code.
- **Follow existing design patterns that comply with these rules.** Study the relevant package and match the established architecture, file placement, and naming. If a convention exists and does not violate these rules, use it. If you have a clear technical reason to deviate, explain the rationale.
- **Reuse existing utility functions**
- **Reuse existing UI components**
- **Verify schema and queries against source files.** Check your ORM schema for table/column structure before writing code that references them.
- **Check existing types before creating new ones** to avoid duplication. Create new types when genuinely needed for new features.
- **Flag security concerns proactively** (exposed secrets, SQL injection, missing auth, etc.).
- **Use parallel tool calls** for independent operations (e.g., reading multiple files, running lint and test simultaneously).
- **Package context awareness:** When working in a specific package, prioritize that package's rule file.
56 changes: 56 additions & 0 deletions .claude/rules/code-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Code Style

## Method Size & Complexity

These are **hard limits**, not guidelines:
- **MAXIMUM 25 lines per method/function** (excluding blank lines and closing braces).
- **MAXIMUM 2 levels of control flow nesting** per method. If you need a third level, extract a method.
- **MAXIMUM 3 parameters** per method. Beyond that, introduce a parameter object or rethink the design.

## YOU MUST USE EARLY RETURNS OVER DEEP NESTING

Guard clauses go at the top. The happy path reads straight down.

## Naming Conventions

Names should be **descriptive and unambiguous**. A reader should never have to look at a method body to understand what it does. Avoid abbreviations.

- **Functions/Methods**: language-idiomatic (snake_case in shell/Python, camelCase in JS/TS) — verbs (`getUserById`, `approve_request`, `calculateTotal`)
- **Types/Classes**: PascalCase — nouns (`InvoiceCalculator`, `ClaimValidator`)
- **Booleans**: prefix with `is`, `has`, `can`, `should` (`isEligible`, `has_access`)
- **Collections**: pluralize (`users`, `active_orders`, `pendingItems`)
- **Constants/env vars**: UPPER_SNAKE_CASE (`ALGORITHM`, `KEY_LENGTH`, `MAX_RETRY_COUNT`)
- **Files**: match the language's idiomatic convention (PascalCase for classes, kebab-case for shell scripts, snake_case for Python modules)

## General Rules

- **Use the language's strongest type discipline** — explicit over implicit. No escape hatches (`any`, untyped `unknown`, `eval`) without justification.
- **Prefer async-first APIs** in languages that support them (`async/await` over raw promises/callbacks).
- **One responsibility per file.**
- **NO MAGIC NUMBERS EVER** — ALWAYS EXTRACT TO A NAMED CONSTANT.

## Code Documentation & Comments

All code must include clear, human-readable documentation. Comments should be written so that a junior-level developer or higher can understand what is being done and why.

**Public APIs are documented.** In languages with doc tooling (TSDoc/JSDoc, Python docstrings, Rustdoc, etc.), document every exported function, method, class, and interface — IDEs surface these as tooltips and they enable automated API-doc generation.

**Required information** (using the language's doc syntax):
- Each parameter's purpose and constraints
- Return value and the conditions producing it
- Exceptions/errors the function may raise
- Usage example for non-trivial functions
- Cross-references to related code or docs
- Deprecation notice with a migration path

**Inline comments** should explain "why," not "what." Comment business logic, workarounds, edge cases, and non-obvious decisions — not obvious code.

## Linting

Linting is enforced via `make lint` (locally) and `.github/workflows/ci.yml` (CI). Required tools:

- **shellcheck** — all `.zsh` and `.sh` files. Configured via `.shellcheckrc` at repo root: `enable=all`, `disable=SC1090` (dynamic source paths are intentional in this project). Any other disables require a comment justifying the exception.
- **shfmt** — `shfmt -d -i 4 -ci -s` (4-space indent, indent case, simplify). Diffs MUST be empty in CI.
- **ruff** — Python files. Configured in `pyproject.toml`. Rules: `E`, `F`, `B`, `D` (docstring checks). Line length 100.

Run `make bootstrap` once to install all linters via Homebrew + pip.
36 changes: 36 additions & 0 deletions .claude/rules/file-organization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# File Organization

## Directory Size Limits

These are **hard limits**, not guidelines:
- **MAXIMUM 10 source files per directory.** Count only source files — colocated test and story files do NOT count toward the cap. If a directory has 10 source files, the next file MUST go in a subdirectory. No exceptions.
- **Colocate test and story files with their source files.** `parser.py` and `parser_test.py` (and any colocated stories/fixtures) belong together in the same directory.

When a directory approaches the cap, group related files into subdirectories by **domain**, **feature**, or **concern** — not by file type. Colocated tests and stories move with their source files into the subdirectory.

## Directory Grouping

When a directory needs subdirectories, group by **domain or feature**, not by file type. Keep related code together — all claim files in one place, not scattered across `types/`, `validators/`, and `handlers/`.

**Exception:** Top-level `src/` directories MAY be organized by architectural layer (e.g., `api/`, `db/`, `event/`) when they represent distinct system boundaries. Within those layers, group by domain.

## Dependency Direction

Imports flow **downward and inward**, never upward or sideways across features.

- **Parent directories MUST NOT import from child route/feature directories.** Shared code lives at the nearest common ancestor.
- **Sibling feature directories MUST NOT import from each other.** If two features need the same code, extract it to their shared parent or a `_shared/` directory.
- **Shared modules are pulled up, never reached into.** If two features both need a utility, it belongs in their common parent — not in one reaching into the other.

## DO NOT MIMIC EXISTING BAD PATTERNS

- **NEVER add files to a directory that already exceeds the 10-file cap.** Flag it to the user and propose a restructuring.
- **When creating new files, follow these rules from scratch** — do not pattern-match against nearby directories that may be poorly organized.

## Code Review Checklist

Before approving any PR, verify:
- [ ] **Is every directory under the 10-file cap (source files only)?**
- [ ] **Are test and story files colocated with their source files?**
- [ ] **Are subdirectories grouped by domain/feature, not by file type?**
- [ ] **Do imports flow downward — no parent importing from child, no sibling cross-imports?**
25 changes: 25 additions & 0 deletions .claude/rules/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Security

## No-Touch Zones

These files require **explicit approval** before any modification:

<!-- Customize per project. Examples: -->
<!-- - `src/crypto/Cryptographer.ts` — Encryption logic -->
<!-- - `src/billing/Calculator.ts` — Financial math -->
<!-- - `prisma/schema.prisma` — Database schema -->

- Any `.env*` files, deployment configs, or CI/CD workflows
- Database migration files
- Authentication/authorization configuration
- Cryptography or encryption modules
- Financial calculation modules
- Files handling user secrets or credentials

## Security Rules

- **NEVER hardcode secrets in source code**
- **NEVER run destructive operations without confirmation** (DROP, TRUNCATE, DELETE without WHERE, `rm -rf`, force-push)
- **Validate all input at trust boundaries** — NEVER TRUST UNTRUSTED INPUT (CLI args, env vars, files, network requests; use Joi/Zod/equivalent for HTTP)
- **Flag security concerns proactively** — exposed secrets, injection (SQL, shell, command), missing auth, XSS, CSRF, etc.
- **Use lossless types for sensitive data** — money in minor units (cents) as integers, never floats; times in epoch ms or ISO 8601
64 changes: 64 additions & 0 deletions .claude/rules/shell-conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Shell Conventions

zsh-specific clarifications of `code-style.md`, `file-organization.md`, and `testing.md`. This file only covers what those rules don't already specify; nothing is repeated.

## Function-line counting

The "25 lines per function" cap counts function-body lines, **excluding** blank lines and lines containing only a closing `}`. Comment lines count.

## Doc-header convention

zsh has no native docstrings. Document every public function with a comment block immediately above its definition with these labelled sections (in this order, each as needed):

```
# <one-line summary, imperative mood, ends with period>
#
# Args: $1 — …, $2 — …
# Returns: 0 on …; non-zero on …
# Errors (stderr): "<exact message>" — <when>
```

Omit `Args:` if the function takes none. Omit `Errors:` if it never writes to stderr.

## Function-name prefixes

Used to encode the dependency direction at a glance and let CI verify it:

- `_core_*` — `lib/core/` (shared primitives)
- `_ckipper_account_*` — `lib/account/` (account subcommands)
- `_ckipper_worktree_*` — `lib/worktree/` (worktree subcommands)
- `_ckipper_config_*` — `lib/config/` (config get/set/unset/list/edit)
- `_ckipper_setup_*` — `lib/setup/` (first-run wizard)
- `_ckipper_run_*` — `lib/run/` (top-level `ckipper run` shortcut)
- `_ckipper_launcher_*` — `lib/launcher/` (bare-`ck` interactive menu)
- `_ckipper_*` — top-level dispatcher in `ckipper.zsh` (and `_ckipper_doctor`, kept un-namespaced because it's exposed as a top-level command, even though its source lives in `lib/account/`)
- No prefix — public, callable from `.zshrc`: `ckipper`, `ck`

## Booleans

zsh has no native bool. Use string values `"true"`/`"false"` and test with `[[ "$x" = "true" ]]`. (Don't use `0`/`1` integers with `(( x ))`.)

## Module sourcing

Modules under `lib/` are sourced once by `ckipper.zsh` (the single entry script sourced from `~/.zshrc`). Modules MUST NOT source siblings.

The `lib/` tree has two layers:

1. **Feature dirs** — `lib/account/`, `lib/worktree/`, `lib/config/`. Each owns a coherent slice of subcommand functionality. Feature dirs MUST NOT call into each other (account cannot call worktree, worktree cannot call config, etc.). Shared code goes in `lib/core/` per `file-organization.md`.

2. **Orchestration dirs** — `lib/launcher/`, `lib/setup/`, `lib/run/`. Their entire purpose is to delegate to feature dirs (the bare-`ck` menu, the first-run wizard, the `ckipper run` top-level shortcut). Orchestration dirs MAY call public, namespaced entry points from feature dirs (e.g. `_ckipper_worktree_dispatch`, `_ckipper_account_add`, `_ckipper_worktree_run`). They MUST NOT reach into another orchestration dir's internals.

`lib/core/` is callable from any layer.

CI enforces the namespace separation via `make lint-merge-guards`. The grep-based guards catch any *reference* (definition or call) — feature siblings cannot reach into each other, and orchestration-only namespaces (`_ckipper_setup_*`, `_ckipper_run_*`, `_ckipper_launcher_*`) are pinned to their dirs:

- `grep -rE '\b_w_[a-z]' lib/` — empty (no leftover renames from the merge)
- `grep -rE '\bW_[A-Z]' lib/` — empty (no leftover globals from the merge)
- `grep -rE '\b_ckipper_account_' lib/worktree/ lib/config/` — empty (sibling features can't call account)
- `grep -rE '\b_ckipper_worktree_' lib/account/ lib/config/` — empty (sibling features can't call worktree)
- `grep -rE '\b_ckipper_config_' lib/account/ lib/worktree/ lib/setup/ lib/run/ lib/core/` — empty (config namespace is pinned to lib/config/)
- `grep -rE '\b_ckipper_setup_' lib/account/ lib/worktree/ lib/config/ lib/run/ lib/core/` — empty (setup namespace is pinned to lib/setup/)
- `grep -rE '\b_ckipper_run_' lib/account/ lib/worktree/ lib/setup/ lib/config/ lib/core/` — empty (run namespace is pinned to lib/run/)
- `grep -rE '\b_ckipper_launcher_' lib/account/ lib/worktree/ lib/setup/ lib/config/ lib/run/ lib/core/` — empty (launcher namespace is pinned to lib/launcher/)

Orchestration dirs (`lib/launcher/`, `lib/setup/`, `lib/run/`) are *omitted* from the account/worktree/config guards by design — that's the dispatcher exception. Adding them would block the only legal pattern of cross-imports.
56 changes: 56 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Testing

## Philosophy

Tests are **documentation** that happens to be executable. A test should read like a specification of behavior.

## Structure: Arrange -> Act -> Assert

Separate the three phases with blank lines:

```python
class TestOrderProcessor:
def test_creates_order_for_valid_request(self):
request = RequestFixture.valid()
processor = build_order_processor()

order = processor.submit(request)

assert order.status == OrderStatus.PENDING
assert order.request_id == request.id

def test_rejects_invalid_requests(self):
request = RequestFixture.invalid()
processor = build_order_processor()

with pytest.raises(InvalidRequestError):
processor.submit(request)
```

## What to Test

- **Processors and business logic** — Always. This is the core of the system.
- **Utility/helper functions** — Always. They're pure and easy to test.
- **Financial calculations** — Always. Money math must be bulletproof.
- **Entry points / handlers** — Integration tests for the happy path and key error cases.
- **Observable behavior, not implementation** — When testing components or modules with internal state, assert on the externally visible outcomes, not on private structure.

## What NOT to Test

- Simple getters/setters or data classes with no logic.
- Framework boilerplate (middleware wiring, route config, loader setup).
- Third-party library behavior.

## Test Doubles

Prefer **hand-written fakes** over mocking libraries. Fakes are simpler, more readable, and catch interface drift at compile time.

## Quality Gates

**Before committing, ALWAYS run** the project's verification commands (build / test / lint / typecheck — whichever apply).

<!-- Add per-package gates as needed. Example:
**Per-package gates:**
- **api:** `npm run typecheck && npm run test && npm run lint`
- **webapp:** `npm run test && npm run lint`
-->
Loading
Loading