My personal Mac setup and configurations
-
Download code:
git clone https://github.com/bertini36/dotfiles.git ~/.dotfiles/ -
Brew packages installation:
brew bundle --file=mac/Brewfile
Package Description batcatwith syntax highlightingezaModern lsreplacementfzfFuzzy finder for the terminal ghGitHub CLI pre-commitGit hook manager graphvizGraph visualization tools jqJSON processor libmagicFile type detection library gotopTerminal system monitor copilot-cliGitHub Copilot CLI (cask) molemacOS disk space cleaner and system optimizer postgresql@18PostgreSQL database pyenvPython version manager uvFast Python package manager [email protected]Python interpreter tldrSimplified man pages with practical examples karabiner-elementsKeyboard remapper (cask) fdFast findreplacementripgrepFast grepreplacementsemgrepStatic analysis (SAST) scanner gitleaksSecret detection in git commits nvmNode version manager pnpmFast Node package manager claudeAnthropic Claude desktop app (cask) claude-codeAnthropic Claude CLI (cask) granolaAI meeting notepad that captures and summarizes meetings (cask) rtkCLI proxy that reduces LLM token consumption by 60-90% herdrTerminal multiplexer that keeps coding agents running in panes handySpeech-to-text utility -
Extra configuration (not available through Brew):
bash mac/config_extras.sh
Config Description gitleakshookGlobal git pre-commit hook for secret detection -
Add fonts (
fonts/) toFont Book -
Configure Karabiner
- Change
Caps LocktoCMD + CTL + Option + Shift - Map F4 to
CMD + Space(Raycast)
- Change
-
Install Oh My ZSH
- Source
shell/.zshrcfrom~/.zshrcso installer appends and machine-specific aliases stay out of the repo:
echo 'source ~/.dotfiles/shell/.zshrc' > ~/.zshrc
-
Install plugins
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions git clone https://github.com/agkozak/zsh-z ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-z
- Source
-
Install Chrome
-
Install Youtube Music (as browser pwa)
-
Install WhatsApp
-
Install Telegram
-
Install Slack
-
Install Claude
-
Install Notion
-
Install Notion Calendar
-
Install Obsidian
-
Install Jetbrains Toolbox and Pycharm
-
Install Visual Studio Code
-
Install Iterm2
- Configure shortcuts following keymap.md
-
Install Docker
-
Install Raycast
- Disable Spotlight shortcut to enable Raycast one (System Preferences -> Keyboard -> Shortcuts -> Spotlight -> Uncheck
Show Spotlight search) - Configure shortcuts following keymap.md
- Disable Spotlight shortcut to enable Raycast one (System Preferences -> Keyboard -> Shortcuts -> Spotlight -> Uncheck
-
Install Amphetamine and set it to keep the computer awake indefinitely
-
Grant Screen Recording permission to your terminal app (System Settings -> Privacy & Security -> Screen Recording):
screencaptureneeds it, and Claude Code usesscreencaptureto screenshot visual changes for a PR (see thecreate-pull-requestskill) -
Enable auto-focus:
defaults write com.apple.Terminal FocusFollowsMouse -bool true -
Install
reviewr, the herdr plugin that reviews an agent's diff in a pane beside it and sends the line comments backherdr plugin install persiyanov/herdr-reviewr
-
Link the rest of configuration files (install Claude Code first so
~/.claude/exists)ln -s ~/.dotfiles/git/.gitignore_global ~/.gitignore_global git config --global core.excludesfile ~/.gitignore_global ln -s ~/.dotfiles/editors/vim/.vimrc ~/.vimrc mkdir -p ~/.config/herdr ln -s ~/.dotfiles/herdr/config.toml ~/.config/herdr/config.toml herdr config check # must print 'config: ok' mkdir -p ~/.config/herdr/plugins/config/persiyanov.reviewr ln -s ~/.dotfiles/herdr/reviewr.toml ~/.config/herdr/plugins/config/persiyanov.reviewr/config.toml ln -s ~/.dotfiles/.claude/settings.json ~/.claude/settings.json ln -s ~/.dotfiles/.claude/statusline-command.sh ~/.claude/statusline-command.sh ln -s ~/.dotfiles/.claude/CLAUDE.md ~/.claude/CLAUDE.md ln -s ~/.dotfiles/.claude/RTK.md ~/.claude/RTK.md ln -s ~/.dotfiles/.claude/skills ~/.claude/skills ln -s ~/.dotfiles/.claude/rules ~/.claude/rules ln -s ~/.dotfiles/.claude/agents ~/.claude/agents ln -s ~/.dotfiles/.claude/hooks ~/.claude/hooks
All Claude Code configuration lives under .claude/ and is symlinked into ~/.claude/.
Note
Remote control is enabled via remoteControlAtStartup in the global settings.
Each session auto-starts the bridge, so it can be driven from
claude.ai/code or the Claude mobile app.
Spec-driven development, opt-in. /start-feature "<task>" runs the full pipeline: a spec, a grilled plan, and a verified implementation, worth it for work that changes architecture, persistent data, or a public contract. Everything else stays a direct conversation, no ceremony paid unless it is asked for explicitly. The superpowers plugin supplies the stages; this repo supplies grilling and fix-until-green around them. Full walkthrough in .claude/skills/start-feature/SKILL.md.
/start-feature "<task>" walks the pipeline, stopping only where it needs you, and always ends on the same Verify β Review β PR β Address feedback β Finish tail.
π orange waits for you Β· π€ gray runs alone Β· β blue runs alone but can interrupt Β· π green are the documents it writes.
flowchart TD
K["π 0 Β· Kick off<br><b>/start-feature</b><br><i>you describe the task, plus the Jira ticket</i>"]
W["π 1 Β· Branch or worktree<br><b>superpowers:using-git-worktrees</b><br><i>the hook provisions the virtualenv<br>in Python worktrees</i>"]
B["π 2 Β· Brainstorm<br><b>superpowers:brainstorming</b><br><i>you answer questions one at a time,<br>then approve the design section by section</i>"]
SPEC[/"π SPEC Β· what and why<br>docs/superpowers/specs/<date>-<topic>-design.md<br><i>you review the file</i>"/]
P["π 3 Β· Plan<br><b>superpowers:writing-plans</b>"]
PLAN[/"π PLAN Β· how, task by task<br>docs/superpowers/plans/<date>-<feature>.md<br><i>you read it</i>"/]
G["π 3 Β· Grill<br><b>grilling</b><br><i>you answer a round at a time until<br>no decision in the plan is fuzzy,<br>then you confirm</i>"]
I["β 4 Β· Implement<br><b>superpowers:executing-plans</b> Β· in session<br><b>superpowers:test-driven-development</b> Β· every task<br><b>superpowers:dispatching-parallel-agents</b> Β· fan-out only<br><i>runs task to task without checking in</i>"]
Y["π€ 5 Β· Verify<br><b>superpowers:verification-before-completion</b><br>fix-until-green Β· on failing checks<br>superpowers:systematic-debugging Β· on surprises<br><i>you get the evidence: tests + pre-commit output</i>"]
R["π 6 Β· Review<br><b>code-reviewer</b> agent on the diff<br><i>plus /security-review when the change<br>touches auth, secrets, or user input</i>"]
PR["π 7 Β· PR<br><b>create-pull-request</b> skill<br>writing-clearly Β· superpowers:finishing-a-development-branch<br><i>you read the title and body before they go out</i>"]
F["π 8 Β· Feedback<br><b>pr-reviewer</b> agent<br><i>you paste the PR link; it closes threads,<br>and you answer human reviewers yourself</i>"]
Z["π 9 Β· Finish<br><i>you merge the PR, then switch to main, pull,<br>and remove the feature branch (and worktree)</i>"]
K --> W --> B --> SPEC --> P
P --> PLAN --> G
G --> I
I -- "stops only on a plan conflict,<br>an implementer question, or BLOCKED" --> Y
Y --> R --> PR --> F --> Z
classDef you fill:#FFE3C2,stroke:#C2410C,color:#111827
classDef auto fill:#E5E7EB,stroke:#6B7280,color:#111827
classDef ask fill:#DBEAFE,stroke:#1D4ED8,color:#111827
classDef doc fill:#DCFCE7,stroke:#15803D,color:#111827
class K,W,B,P,G,R,PR,F,Z you
class Y auto
class I ask
class SPEC,PLAN doc
This pipeline only runs behind /start-feature. Nothing routes a task into it automatically; anything not started that way is a direct conversation, no spec, plan, or grill imposed.
Five rules never bend:
- No fuzzy decisions.
grillinginterviews you in rounds until every decision is settled. It ends when you confirm the understanding is shared, not when it runs out of questions. - A plan names its harness. Every behavior the plan promises says which test fails when it breaks. A spec is only as solid as the thing that checks it.
- Subagents fan out, they do not relay. A dependent chain stays in one session. Subagents take work that shares no state and no ordering: sweeping for references, auditing an area, getting oriented.
- The diff is reviewed once.
code-revieweraudits it at stage 6.pr-reviewerthen owns the open threads, not a second pass over the same code. - Humans answer humans.
pr-reviewercloses your threads and bot threads. Another person's thread stays yours, even when you asked for the fix.
Reusable AI agent skills that Claude invokes autonomously when a task matches their description. Any skill can also be invoked explicitly as a slash command (/skill-name).
The MCPs column lists the MCP servers a skill needs. Required servers must be connected before the skill runs, otherwise it stops. Optional servers only add enrichment, or cover one input type among several, and the skill degrades gracefully without them. See Per-project plugins and Installing and updating for how to connect each one.
| Skill | Description | MCPs |
|---|---|---|
create-pull-request |
Create a GitHub PR following project conventions using gh CLI, with a screenshot attached when the change has a visual surface |
None |
django-patterns |
Django architecture, REST APIs with Pydantic, ORM best practices, caching, and signals | None |
domain-service-layer |
Where business logic lives in a Django app: domain services own the rules, views do HTTP, factories wire the dependencies | None |
explain |
Turn a link into a local HTML page that explains it visually, with diagrams built from pure CSS and inline SVG, then open it in Chrome via /explain |
Optional: atlassian for Jira and Confluence links, notion for Notion links. Other link types use WebFetch and gh |
fix-until-green |
Loop project checks and pre-commit until green or 5 iterations, fixing each failure against its full output | None |
grilling |
Grill the user relentlessly about a plan, decision, or idea, interviewing in rounds until every decision is settled (source) | None |
herdr |
Drive herdr through its CLI: inspect panes, tabs and workspaces, split layout, start sibling agents and read their output (source) | None |
investigate-sentry |
Investigate a Sentry exception down to root cause and propose a fix | Required: sentry. Optional: datadog-mcp to correlate the request behind the exception |
memento |
Morning briefing from the previous working day's Granola meetings and Slack conversations: up to 5 importance-sorted points, action-flagged, with the review window resolved against Google Calendar | Required: granola, slack, google-calendar (all three checked in a preflight gate) |
python-code-style |
Python type safety, generics, protocols, and advanced type annotations | None |
save-session |
Save a high-density summary of the current session to .claude_sessions.md |
None |
start-feature |
Start the feature development pipeline, via /start-feature only |
None |
tldr |
Quick bullet summary of a URL (article, blog post, video) via /tldr |
None |
writing-clearly |
Clear prose for docs, commits, error messages, and UI text | None |
Some skills carry an evals/evals.json file that defines test cases to measure skill effectiveness: create-pull-request, django-patterns, python-code-style, and writing-clearly. To run the evals, paste the following steps into your AI agent prompt.
- Read the eval definitions in
.claude/skills/<skill>/evals/evals.json - Generate outputs - run each eval prompt twice per skill (once with the skill loaded, once without) and save the results to
.claude/skills-workspace/iteration-1/<eval-id>/with_skill/outputs/andwithout_skill/outputs/ - Create
eval_metadata.json- record the assertions from each eval's expectations array alongside references to the output files - Compare outputs in
with_skill/outputs/vswithout_skill/outputs/ - Verify each assertion from
eval_metadata.jsonagainst the corresponding output
Specialized subagents that run in isolated context windows with restricted tools.
| Agent | Description |
|---|---|
code-reviewer |
Read-only diff audit with an A-F graded report (architecture, security, performance, quality, testing) and explicit agent-authored red flags |
pr-reviewer |
Closes out a PR's open review comments: fetches, triages, fixes, commits, pushes, replies, resolves threads, and verifies CI |
Path-scoped rules that load automatically only when working on matching files.
| Rule | Scope |
|---|---|
python |
**/*.py - Python 3.13+ conventions, ruff, uv, naming, imports |
django |
Django files (views, models, urls, admin, etc.) - architecture plus N+1 prevention, batch writes and query-count guards |
tests |
Test files - no comments, self-explanatory naming |
Shell scripts in .claude/hooks/ that the harness runs around tool calls and
session events. Registered in the hooks block of .claude/settings.json.
| Hook | Event | Description |
|---|---|---|
python-worktree-venv.sh |
SessionStart |
Provisions the virtualenv when a session starts inside a Python git worktree |
git-protected-branches.sh |
PreToolUse (Bash) |
Denies any push to main or master and any rewrite of their history (amend, rebase, moving reset, forced branch moves, filter-repo); stays silent for everything else |
rtk hook claude also runs on every Bash call to rewrite commands through the
rtk proxy.
Plugins are split into two tiers to keep session context lean: a small global
set enabled for every session, and domain-specific plugins enabled only in the
projects that need them. All marketplaces are registered globally in
extraKnownMarketplaces of .claude/settings.json.
Enabled in enabledPlugins of the global settings:
| Plugin | Description |
|---|---|
superpowers |
Spec driven development (SDD) based on brainstorming, planning, subagent-driven execution, TDD, and code review skills |
skill-creator |
Create, modify, and benchmark custom skills, including eval runs and description optimization |
context7 |
Up-to-date documentation and code examples for any library |
caveman |
Caveman-speak mode that cuts ~75% of output tokens while keeping technical accuracy |
last30days |
Research any topic across Reddit, X, YouTube, HN, Polymarket, and the web, scored by upvotes, likes, and real money |
Enable these in the project's .claude/settings.json:
| Plugin | Description |
|---|---|
sentry-skills |
Sentry engineering skills: PR writing, code review, Django patterns, security review, and more |
notion |
Read and manage Notion pages and databases |
figma |
Read Figma designs and generate code from them |
atlassian |
Jira and Confluence: issues, backlogs, status reports, and knowledge search |
datadog-mcp |
Datadog observability: logs, metrics, traces, incidents, monitors, and dashboards |
{
"enabledPlugins": {
"figma@claude-plugins-official": true,
"sentry-skills@sentry-skills": true
}
}On a fresh machine, install the third-party plugins (the marketplaces are already registered through the tracked settings):
claude plugin marketplace add JuliusBrussee/caveman
claude plugin install caveman@caveman
claude plugin marketplace add mvanhorn/last30days-skill
claude plugin install last30days@last30days-skilldatadog-mcp is an MCP server rather than a plugin; install it with:
claude mcp add --transport http datadog-mcp https://mcp.datadoghq.eu/api/unstable/mcp-server/mcpGranola (installed via the Brewfile cask) also ships an official MCP server that exposes meeting notes and transcripts. Register it globally; the first connection opens an OAuth flow in the browser, no API key needed. Requires a signed-in Granola app (macOS 12+, Google or Microsoft account, microphone permission):
claude mcp add --transport http --scope user granola https://mcp.granola.ai/mcpsentry, slack, and google-calendar are hosted connectors rather than local
plugins. Enable them from the connectors directory at
claude.ai and authenticate once; they then appear as MCP
tools in Claude Code sessions.
To update everything, ask Claude in a session: Update installed plugins.
CLI tools that complement Claude Code. They are installed outside the plugin system but configured from this repository.
rtk proxies common dev commands and strips
their output down to what the model needs (60-90% token savings). A
PreToolUse hook in the global settings rewrites Bash commands through it
transparently. Activate with:
rtk init -gOnly the mcpServers block is tracked. The rest of
claude_desktop_config.json (account UUIDs, window state, onboarding flags)
is local runtime state that shouldn't be versioned.
- Real config:
~/Library/Application Support/Claude/claude_desktop_config.json - Tracked copy:
mac/claude/mcp_servers.json
Setup on a fresh machine:
mkdir -p ~/Library/Application\ Support/Claude
# File doesn't exist yet:
cp ~/.dotfiles/mac/claude/mcp_servers.json \
~/Library/Application\ Support/Claude/claude_desktop_config.json
# File already exists: merge mcpServers into it instead of overwriting
# (shallow merge, so a tracked server entry fully replaces any stale match)
jq -s '.[1] + {mcpServers: ((.[1].mcpServers // {}) + .[0].mcpServers)}' \
~/.dotfiles/mac/claude/mcp_servers.json \
~/Library/Application\ Support/Claude/claude_desktop_config.json \
> /tmp/claude_desktop_config.json \
&& mv /tmp/claude_desktop_config.json \
~/Library/Application\ Support/Claude/claude_desktop_config.jsonRestart Claude Desktop for the change to take effect. After adding a new MCP
server by hand, copy the updated mcpServers block back into
mac/claude/mcp_servers.json to keep it tracked.
google-health-mcp-unofficial
reads user-authorized Google Health API v4 data (Fitbit, Pixel Watch)
locally over OAuth; tokens never leave the machine and live at
~/.google-health-mcp/tokens.json.
Setup on a fresh machine, after the MCP entry above is in place:
-
Create a Google Cloud OAuth client, enable the Google Health API, and add the redirect
http://127.0.0.1:3000/callback. -
Run:
npx -y google-health-mcp-unofficial setup --scope-preset full npx -y google-health-mcp-unofficial auth npx -y google-health-mcp-unofficial doctor
On a headless host (SSH, no browser) use
auth --manualinstead; see docs/oauth.md. -
doctor --livecalls safe Google Health identity/profile endpoints to confirm the API is reachable end to end.
Built with β€οΈ from Mallorca