dotfiles for AI coding agents

ctrl+shft

ctrl defines the rules.
shft executes them.

Every developer using Claude Code or Copilot hits the same walls. Context degrades mid-task. Instructions drift between machines. Secrets leak into the conversation. Irrelevant rules load for every project. One repo fixes all four — and hardens AFK Docker runs with per-iteration, short-lived credentials instead of long-lived token reuse.

# bootstrap in two commands
git clone https://github.com/arndvs/ctrlshft.git ~/dotfiles
✓ cloned
 
bash ~/dotfiles/bin/bootstrap.sh
✓ CLAUDE.md symlinked
✓ instructions loaded via CLAUDE.md
✓ skills/ → ~/.claude/skills/
✓ agents/ → ~/.claude/agents/
✓ rules/ → ~/.claude/rules/
✓ secrets/ created from templates
✓ shell integration wired
✓ ctrl & shft CLI → ~/.local/bin/
✓ Python .venv deps installed (incl. PyJWT)
✓ supply chain hardened
 
ctrl+shft ready — type ctrl help to explore
 
ctrlshft:~
context integrity  ·  cross-machine sync  ·  secret isolation  ·  progressive context loading  ·  autonomous loops  ·  surgical changes  ·  context integrity  ·  cross-machine sync  ·  secret isolation  ·  progressive context loading  ·  autonomous loops  ·  surgical changes  ·  context integrity  ·  cross-machine sync  ·  secret isolation  ·  progressive context loading  ·  autonomous loops  ·  surgical changes  · 
01 — THE PROBLEM

Every developer
hits the same walls

Context Decay

Context degrades mid-task. The agent repeats itself, compaction loses nuance, quality drops. A fresh conversation has no idea where things left off.

Instruction Drift

Instructions drift between your laptop and VPS. Different machines run different rules. There's no single source of truth.

Secret Exposure

Secrets leak into agent context. API keys, tokens, passwords visible inside the conversation — or worse, logged somewhere they shouldn't be.

Rule Pollution

Irrelevant rules load for every project regardless of stack. Next.js rules on a PHP project. PHP rules in a Python repo. Noise drowning signal.

02 — HOW IT WORKS

One repo,
every machine

Context Integrity
Persistent Plans

When context gets high, the agent writes its plan to working/. A fresh conversation continues exactly where the old one left off — no repetition, no lost nuance.

working/
└─ plan.md    # persisted state
└─ research.md # cached explorations
Stack-Aware Rules
Progressive Loading

detect-context.sh scans your working directory. A Next.js project loads Next.js rules. Nothing from PHP. Nothing from Python. Only what matches.

# auto-detected on cd
ACTIVE_CONTEXTS=general,nextjs,node,ts
# loads matching instructions/*.md
Secret Isolation
Three-Tier Secrets

Three tiers: config agents can see, credentials scoped to a child process, and AFK iteration tokens (short-lived GitHub App installation tokens) minted per loop. run-with-secrets.sh injects API keys into a child process — they vanish on exit. Deny rules block env, printenv, and cat secrets/*.

.env.agent   # agent-visible config
.env.secrets # process-scoped only
# credentials vanish on exit
Git-Synced
Clone Once, Pull Forever

Clone to ~/dotfiles on your laptop, your VPS, anywhere. git pull updates every machine simultaneously. Bootstrap is idempotent — safe to re-run anytime.

# update everywhere at once
cd ~/dotfiles && git pull
bash bin/bootstrap.sh
03 — THE PIPELINE

Intent to
commit

/grill-me
Interrogate you about a feature until shared understanding. One question at a time, recommended answers.
/write-a-prd
Explore codebase, interview you, sketch module boundaries, write Product Requirements Document (PRD), submit as GitHub issue.
/architect
Plan implementation — vertical slices, dependency graphs, acceptance criteria. Designs the how before building starts.
/prd-to-issues
Break the PRD into vertical slices. Label each AFK or HITL. Create GitHub issues with dependencies.
/do-work
Understand → Plan → Implement → Validate → Commit. Auto-detects your stack's feedback loops. Loops until done.
shft
Pick issues from the backlog, implement in a Docker sandbox, commit, repeat. Runs AFK until backlog is empty.
04 — SKILLS

What the
agent knows

/do-work
Understand → Plan → Implement → Validate → Commit
/grill-me
Interrogate until shared understanding, one question at a time
/write-a-prd
Explore, interview, write PRD, submit as GitHub issue
/prd-to-issues
Break PRDs into labeled vertical slices
/architect
Vertical slices, dependency graphs, acceptance criteria
⚡ auto-invoke
skill-scaffolder
Scaffold new skills from production-tested patterns
explore
Decompose, spawn parallel sub-agents, synthesize summary
⚡ auto-invoke
research
Cache exploration into research.md with lifecycle management
⚡ auto-invoke
codebase-audit
Real problems only, grouped by severity. No manufactured issues.
⚡ auto-invoke
improve-architecture
Shallow-module clusters → parallel design agents → GitHub RFC
⚡ auto-invoke
/tdd
Red-green refactor. Failing test → implement → refactor.
systematic-debugging
Root-cause-first — investigate → pattern → hypothesis → fix
⚡ auto-invoke
atomic-commits
Branch-isolated atomic commits. Survey diff, group by seam, commit or ship (push + PR).
⚡ auto-invoke
/review
Focused review of staged changes. Edge cases, logic errors, integration risks.
/document
Write, update, or audit documentation. Accurate, minimal, audience-appropriate.
sanity-best-practices
Schema design, GROQ, TypeGen, Visual Editing, Portable Text, integrations.
compliance-audit
Auto-invoked after do-work/tdd/debugging. Rule-by-rule review, violation flagging.
⚡ auto-invoke
stress-test
Adversarial 19-scenario protocol. Validates rule compliance boundaries.

How auto-invoke works: Every skill's description is loaded into the agent's system prompt at session start. Skills marked ⚡ have broad descriptions that match common task patterns — the agent loads them automatically when it detects a matching situation. No slash command needed. They act as passive quality guardrails: same rigorous process every time, without you remembering to ask.

+ Add private skills: skills/_local/your-skill/SKILL.md — auto-discovered, gitignored.

05 — SUBAGENTS

Isolated
specialists

Each subagent runs in an isolated context window with its own system prompt and tool restrictions. Exploration stays out of your main conversation.

code-reviewer
Bugs, security, logic errors — not style nits. Finds what actually matters in a diff.
sonnetread-onlypersistent memory
researcher
Deep codebase exploration, architecture mapping. Builds a mental model without polluting yours.
sonnetgrep / globpersistent memory
security-auditor
OWASP Top 10, secrets exposure, config hardening. Paranoid by design.
sonnetread-onlypersistent memory
06 — PRINCIPLES

Baked-in
discipline

Four behavioral rules in global.instructions.md, addressing the most expensive AI failure modes: building wrong things, overengineering, drive-by refactoring, and vague success criteria — derived from Andrej Karpathy's observations on LLM coding pitfalls and adapted here for this workflow to bias toward correctness over speed.

1
Think Before Coding

Surface confusion before acting. Present multiple interpretations. Name assumptions explicitly. Push back when simpler exists. Clarifying questions come before implementation, not after a wrong turn.

"Stop when confused — ask, never pick an interpretation silently."
2
Simplicity First

Minimum code that solves the problem. No speculative features. No abstractions for single-use code. If 200 lines could be 50, rewrite it. Prefer straightforward solutions a senior engineer would call obvious and maintainable.

"Would a senior engineer say this is overcomplicated? If yes, simplify."
3
Surgical Changes

Touch only what you must. Match existing style exactly. Don't refactor what isn't broken. Every changed line traces to the user's request. Mention adjacent issues, but don't fold unrelated cleanup into the same diff.

"Mention unrelated dead code — don't delete it."
4
Goal-Driven Execution

Define success criteria. Loop until verified. Transform imperative tasks into verifiable goals with acceptance criteria at each step. Convert vague asks into outcomes that can be tested and proven.

"Write a test that reproduces it, then make it pass."
How you know it's working: fewer unnecessary diff lines, fewer overengineered rewrites, cleaner scope boundaries, and verification steps that are visible before a task is marked done.
07 — SECURITY

Agents see config,
never credentials

Three tiers. Config lives in shell, run-with-secrets.sh injects credentials into a child process only, and AFK loops use AFK iteration tokens (short-lived GitHub App installation tokens) minted per loop. Deny rules block any attempt to read secrets.

File In Shell? Agent-Visible? Contains
.env.agent YES YES Usernames, hosts, IDs
.env.secrets NO NO API keys, tokens, passwords
AFK iteration token NO NO Minted per loop, expires ~1h
Deny rules block env, printenv, cat secrets/*, and echo $*KEY* at the agent level. Agents can't accidentally inherit what they can't see.
AFK hardening path: one token per Docker iteration, no PAT fallback in AFK mode, fail closed when mint fails.
08 — HOOKS

Guardrails that
never sleep

Claude Code hooks fire on lifecycle events — before tools run, when the agent stops. Shell scripts receive JSON on stdin, return exit codes. No model judgment required.

secret-guard
Blocks credential-exposing commands before they execute. Defense-in-depth alongside deny rules.
PreToolUseBash
migration-guard
Blocks database migrations targeting non-test databases. Requires explicit confirmation before proceeding.
PreToolUseBash
format-check
Detects Biome, Prettier, or ESLint and formats all modified files when the agent stops.
Stopnon-blocking
typecheck
Runs tsc --noEmit on TypeScript projects. Blocks the agent from stopping until types pass.
Stopblocking
compaction-guard
Blocks auto-compaction at ~95% context. Directs the agent to commit work and follow the handoff protocol instead of losing nuance.
PreCompactblocking
context-warning
Graduated context warnings at 40% and 70% usage. Injects advisory messages without blocking prompts. Stub — pending statusLine experiment.
UserPromptSubmitstub
How it works: Scripts in hooks/ receive JSON on stdin, check conditions, return exit code 0 (allow) or 2 (block). Bootstrap symlinks hooks/~/.claude/hooks/ and merges configuration into ~/.claude/settings.json.
09 — HUD

See what your
agent actually does

The HUD is a real-time HUD that shows which rules loaded, which skills fired, which projects are being touched, and whether compliance checks pass or fail. It runs locally and updates instantly via WebSocket.

ctrl+shft HUD — real-time HUD showing project tabs, loaded rules and skills, session log, and compliance history
Multi-project tracking
Every project the agent touches gets its own tab — dotfiles, client projects, anything. Cross-project reads detected automatically via git root.
Live compliance rate
Rolling compliance percentage across sessions with trend sparkline, violation count, and per-day history chart.
Context & file inventory
Which stack contexts are active, which instructions/skills/rules/agents loaded, with read timestamps and loaded/available badges.
Session event log
Chronological stream of every event — context changes, task bookends, file reads, compliance results. Filterable by type.
Zero-dependency daemon
Node.js daemon with no required npm packages. Named pipe transport (<1ms latency), HTTP POST fallback, optional SQLite persistence.
WebSocket + HTTP
Real-time updates via ws://localhost:7822. Falls back to HTTP polling. Single-file frontend — no build step.
Start it: ctrl hud (or bash ~/dotfiles/bin/start-hud.sh) — then visit localhost:7823. Hooks emit events automatically. No configuration required.
10 — SHFT

ctrl defines the rules.
shft executes them.

Not a framework. A bash loop that runs Claude against your GitHub issues backlog — sandboxed in Docker for AFK mode, direct on host for HITL. Exits when the backlog is empty.

Human In The Loop
HITL
Runs once while you watch. Use when learning, reviewing each step, or validating a new task type before going fully autonomous.
Away From Keyboard
AFK
Loops in Docker sandbox. Claude picks a task, implements, commits, closes the issue, picks the next. You review PRs async.
Requires Claude Max, Docker Desktop, and 5–10 well-formed GitHub issues. AFK also requires jq and srt on PATH.
11 — CLI REFERENCE

Every command,
at a glance

ctrl — infrastructure

Infrastructure
ctrl check
Validate symlinks + environment
ctrl check --afk
AFK mode validation (jq, srt, GitHub App creds)
ctrl bootstrap
Run bootstrap alias: boot
ctrl sync
Git pull + bootstrap + reload shell
ctrl sync-settings
Merge managed VS Code settings
ctrl status
Contexts, client, symlinks, HUD
ctrl context
Detect and display active contexts alias: ctx
HUD
ctrl hud
Start the compliance HUD
ctrl hud stop
Stop the HUD daemon
ctrl hud status
Check if running
ctrl hud restart
Stop + start
ctrl hud logs [-f]
Show daemon log (-f to follow)
ctrl hud events
Recent events for current project
ctrl hud violations
Violations for current project
ctrl hud state
Full debug state dump (JSON)
ctrl hud clear
Clear events for a project
ctrl hud open
Open HUD in browser
ctrl hud url
Print the HUD URL
ctrl hud --fg
Run in foreground (debug mode)
Client management & credentials
ctrl new-client
Onboard a new client alias: client
ctrl migrate
Read-only diagnostic for existing setups
ctrl uninstall
Safely remove ctrl+shft
ctrl verify-token
Test-mint a GitHub App token
Session analysis (requires sheal)
ctrl retro
Session retrospective → dotfiles
ctrl digest
Categorized prompt digest
ctrl cost
Token cost dashboard
ctrl ask "question"
Search across session transcripts
ctrl learn
Manage session learnings
ctrl version
Show version
ctrl help
Show all commands

shft — autonomous execution

Running
shft run
HITL — run once while you watch alias: hitl, once
shft afk [n]
AFK — autonomous loop (default 5)
shft afk --force
Skip pre-flight validation
Monitoring
shft status
Is a loop running? How many issues open?
shft stop
Stop AFK loop after current iteration
shft log [-f]
Show shft log (-f to follow) alias: logs
Work queue
shft issues
List open issues in priority order alias: queue
shft next
Show the next issue shft would pick
shft done [n]
Show last n closed issues alias: recent
shft context
Show what the agent sees at start alias: ctx
Plan
shft plan
View working/plan.md
shft plan edit
Open plan in $EDITOR
shft plan clear
Clear the plan file
Credentials & config
shft validate
Run AFK pre-flight checks alias: check
shft mint
Test-mint a GitHub App token
shft prompt
Show shft/prompt.md
shft version
Show version
shft help
Show all commands
12 — FAQ

Due
diligence

You shouldn't adopt anything that touches your global config without knowing exactly what it does, what it writes, and how to get out. Here's everything.

Dotfiles
What are dotfiles, and why does ctrl+shft live there?

Dotfiles are configuration files in your home directory — named with a leading dot (.bashrc, .gitconfig) so they're hidden by default. Developers store them in a git repo and symlink them into place, so their entire environment syncs across every machine with a git pull.

Claude Code follows the same convention: it looks for CLAUDE.md and .claude/ in your home directory for global instructions, skills, and agents that apply to every project. That makes ~/dotfiles the natural home — bootstrap symlinks everything into place so your agent gets the same context on your laptop, VPS, or a fresh machine.

Removal
Can I remove it without it tanking my setup?

Yes. Run the uninstall command:

ctrl uninstall

Or directly: bash ~/dotfiles/bin/uninstall.sh

It removes only the symlinks and shell integration that bootstrap created — nothing in your project repos, nothing else in ~/dotfiles. If you had dotfiles there before installing ctrl+shft, they're untouched.

Removal
What if the project goes stale — am I stuck with it?

No. Since you fork before cloning, your fork is your source of truth. Stop pulling upstream whenever you want. The tool keeps working exactly as-is — no upstream dependency, no breaking changes you didn't ask for. And if you want out entirely, ctrl uninstall cleans it up in one command.

Setup
Does it require sudo or admin to install?

No. Everything installs into your home directory — ~/dotfiles, ~/.claude/, ~/.bashrc. No system-level writes, no elevated permissions required.

Setup
I already have a CLAUDE.md — will this overwrite it?

Depends where it lives. A CLAUDE.md in a project repo is untouched — project-level config always takes precedence over global. If you already have ~/.claude/CLAUDE.md, bootstrap replaces it with a symlink (printing a message). Back it up first and fold your content into CLAUDE.base.md. Use --adopt to merge your existing config.

Setup
What exactly does it write to my machine?

Full footprint from bootstrap:

# symlinks
~/.claude/CLAUDE.md
~/.claude/skills/
~/.claude/agents/
~/.claude/rules/
~/.claude/commands/
~/.claude/hooks/
~/.copilot/skills/
~/.agents/skills/

# files created / merged
~/.claude/settings.json
~/dotfiles/secrets/.env.agent
~/dotfiles/secrets/.env.secrets
~/dotfiles/secrets/.venv

# CLIs installed to ~/.local/bin/
ctrl
shft

# shell appends (~/.bashrc and ~/.zshrc)
load-secrets snippet
context-detection on cd

# supply chain hardening
~/.npmrc              # min-release-age=7
~/.config/uv/uv.toml  # exclude-newer

uninstall.sh reverses all of it.

Security
Why does it need a GitHub App? Can I use a PAT instead?

A PAT works for HITL mode. AFK mode structurally blocks the PAT path — the validator enforces this at startup, so it's not just discouraged, it's unavailable.

The reason: static credentials create long-lived compromise windows across runs. Instead, a three-tier model keeps secrets out of agent context entirely:

.env.agent
Agent-visible config only — usernames, hosts, IDs
.env.secrets
Process-scoped credentials injected via run-with-secrets.sh — never exported to shell
AFK token
Minted fresh per Docker run, 1-hour TTL, never persisted
Before each AFK loop, a Python helper signs a JWT using the GitHub App private key and injects the resulting short-lived token into that container's runtime context only. If minting fails, the iteration aborts — no fallback to static credentials.
Security
What does the agent actually have permission to do in AFK mode?

It runs inside a Docker sandbox with the minimum GitHub App permissions you configure: Contents, Issues, and Pull Requests (read/write). It cannot access other repos, org settings, or anything outside that scope.

Deny rules block it from reading secrets or env vars — even ones technically in scope. env, printenv, cat secrets/*, and echo $*KEY* are all blocked at the agent level.

Security
How do I audit what rules and skills are loaded at any given time?

Run ctrl context in any directory — it prints the active contexts and which rule files are loaded. Narrow-scope skills are invoked explicitly. Skills marked ⚡ auto-invoke (like systematic-debugging and compliance-audit) are loaded automatically when the agent detects a matching pattern.

ctrl context
# → ACTIVE_CONTEXTS=general,nextjs,node,ts
# → loaded: instructions/nextjs.md
Rules
Does it work well alongside existing rules?

Yes. detect-context.sh only loads rules matching your current stack — it doesn't clobber existing config. If you already have a CLAUDE.md in a project repo, that takes precedence. It stays out of your way.

Rules
Can I use this with the Claude API directly, or only Claude Code?

Currently optimized for Claude Code — that's where CLAUDE.md, skills, and agents are natively picked up. The rules and principles are plain markdown, so nothing stops you referencing them in your own API prompts, but the automatic loading and context detection are Claude Code features.

Cost
Does this require Claude Max, or does it work on Pro?

HITL mode works on any Claude plan. AFK mode — autonomous loops running potentially hundreds of turns overnight — is designed for Claude Max where usage limits won't interrupt a run mid-task. Pro limits will likely cut a long AFK session short.

Cost
Does it significantly increase token burn?

For normal HITL use, minimal — skills only load when invoked, not on every prompt. For AFK loops, burn scales with backlog size and task complexity. A well-scoped issue on a mid-size codebase typically runs 20–50k tokens. A backlog of 10 issues could be 200–500k tokens overnight.

Monitor your first few runs to baseline before going wide.

Ongoing Use
How do I pull upstream updates without clobbering my personal config?

Your personal config lives in gitignored files: secrets/.env.agent, secrets/.env.secrets, skills/_local/, and instructions/_local/. None are tracked, so git pull upstream main never touches them.

git pull upstream main
bash ~/dotfiles/bin/bootstrap.sh # regenerates CLAUDE.md
Ongoing Use
What breaks if I don't re-run bootstrap after a git pull?

Symlinks survive pulls — your Claude setup keeps working. The main thing that goes stale is CLAUDE.md if CLAUDE.base.md changed upstream. Bootstrap regenerates it. It's idempotent, so re-running is always safe.

Compliance
How do I know the agent is actually following the rules, not just loading them?

"Read X" confirms a rule was loaded into context — not that it was followed. The compliance-audit skill closes the gap: after each task it reviews the diff against every active rule, logs pass/fail/warn to working/compliance-log.md, and the HUD surfaces compliance rates across sessions in real time.

Run /stress-test for adversarial verification before deploying in a team environment. Current compliance on well-formed tasks: ~85–90%, with known failure modes documented and actively tracked.

13 — CONTRIBUTORS

Built in
the open

Fetching contributors
Live from GitHub API · Top contributors shown
Fork on GitHub → Contributing guide → All contributors → MIT License · contributions welcome
14 — INSTALLATION

Running in
minutes

# Fork at github.com/arndvs/ctrlshft/fork, then:
git clone https://github.com/YOUR_USERNAME/ctrlshft.git ~/dotfiles
Fork first so you can push your own customizations. Always clone to ~/dotfiles — hardcoded across 40+ references.
bash ~/dotfiles/bin/bootstrap.sh
# after install: ctrl bootstrap
Idempotent. Symlinks CLAUDE.md, skills/, agents/, rules/, commands/, hooks/. Merges hook config into ~/.claude/settings.json. Creates secrets from templates. Wires shell integration. Installs Python deps into secrets/.venv (including PyJWT for AFK GitHub App token minting).
Do this once, in order: create and install the app, set secrets, then validate.
  1. 1Create the App at github.com/settings/apps/new.
  2. 2Set Homepage URL to your own GitHub dotfiles repository URL (e.g. https://github.com/<you>/dotfiles).
  3. 3Use minimum permissions: Contents (R/W), Issues (R/W), Pull requests (R/W), Workflows (R/W only if AFK edits workflow files). Disable webhook.
  4. 4Install the app on your target repo (Install App → Only select repositories → pick repo). That should be the same dotfiles repo you created.
  5. 5Copy installation ID from github.com/settings/installations/<id>.
$EDITOR ~/dotfiles/secrets/.env.agent   # non-sensitive config
$EDITOR ~/dotfiles/secrets/.env.secrets # process-scoped credentials

# Required for AFK credential rotation:
GITHUB_APP_ID=...
GITHUB_APP_INSTALLATION_ID=...
GITHUB_APP_PRIVATE_KEY_B64=...
Base64 your private key to one line (Git Bash: base64 -w 0 ~/Downloads/your-app-key.pem) and place all three values in secrets/.env.secrets.
bash ~/dotfiles/bin/validate-env.sh --afk
bash ~/dotfiles/bin/verify-github-app-token.sh
# after shell reload: ctrl check --afk && ctrl verify-token
Expected output: mint_success=yes, expires_at=..., token_len=40.
Windows: if python3 opens Microsoft Store, AFK scripts use secrets/.venv Python first. Re-run bootstrap.sh if venv is missing.
If token minting reports missing PyJWT or requests, re-run bash ~/dotfiles/bin/bootstrap.sh.
If minting fails with status=404, recheck installation ID, app install target, and key/app pairing.
If a raw token is ever printed, rotate App private key immediately, update GITHUB_APP_PRIVATE_KEY_B64, then rerun mint verification.
bash ~/dotfiles/bin/sync-settings.sh
# after shell reload: ctrl sync-settings
Enables the instruction discovery chain. Run with --dry-run first to preview changes.
source ~/.bashrc   # bash
source ~/.zshrc    # zsh
Activates context detection on cd and secret loading.
View on GitHub → Contributing guide →
MIT License  ·  macOS / Linux / WSL
ctrl+shft  ·  define the rules  ·  execute the work  ·  git pull to update everywhere  ·  credentials vanish on exit  ·  context persists between conversations  ·  ctrl+shft  ·  define the rules  ·  execute the work  ·  git pull to update everywhere  ·  credentials vanish on exit  ·  context persists between conversations  ·