dotboost

Claude Code, already fluent in Dotkernel.

dotboost is one directory you copy into a Dotkernel project. Claude arrives knowing where a module goes, which naming dialect the app uses and how its responses are built — and knowing which files it must never open.

$ git clone --depth 1 https://github.com/dotkernel/dotboost.git .dotboost && cp -r .dotboost/.claude .claude && rm -rf .dotboost

No git on the machine? Take the zip instead. Either way there is one more step — the executable bits.

Not an application. A configuration.

The repository is not a Dotkernel app you build on. Its entire payload is the .claude/ directory: permission rules, six hooks, a status line, a review subagent, ten /dk-* commands and seventeen skills.

Every skill detects the variant before it answers — API, Admin, Frontend, Light, Queue, or a project derived from one of them — and applies the matching dialect. Handler naming, authorization keys and response shape differ between them, and a wrong guess is the kind of mistake that survives review.

The first thing you see is the session-start briefing.

SessionStart hook
variant        Dotkernel API
namespace      Api\
authorization  RBAC via config/autoload/authorization.global.php
branch         feature/wallet-ledger
feature docs   documentation/features/ (14 docs)
missing        config/autoload/local.php  — copy from .dist
line endings   ok (lf)
What lands in the project
<project>/.claude/
├── settings.json      guardrails, hooks, status line
├── settings.local.json.example
├── statusline.sh      5h / 7d account usage
├── markdownlint.jsonc
├── hooks/             six bash hooks
├── agents/            the review subagent
├── commands/          ten /dk-* commands
└── skills/            seventeen skills

Six hooks that run whether or not Claude cooperates

Skills are advice. Hooks are enforcement — they sit in front of the tool call, so a compound command cannot slip past them.

guard-protected-pathsRefuses edits to vendor/, migrations, dependency manifests, uploads, logs and key material. A blocked *.local.php edit is redirected to its .dist template.
guard-bashRefuses installs, destructive git, DB-mutating commands and development-mode toggles — including inside cd src && composer require foo.
normalize-fileBOM, CRLF, trailing whitespace, final newline. Leaves the two trailing spaces that mean a line break in markdown.
php-lintphp -l on every PHP file Claude writes. Report-only.
markdown-lintmarkdownlint-cli2 on every markdown file, against the shipped rule set. Silent when the binary isn't installed.
session-startThe briefing above: variant, namespace, authorization style, branch, setup gaps.

Your credentials never enter the context window

This is the part worth adopting the file for. settings.json is committed and carries opinions, not only protection — sessions start in plan mode, so Claude proposes before it edits.

Never read

Read denies, not write protection. The contents are never sent at all.

  • .env
  • *.local.php
  • config/autoload/local.php
  • data/oauth/

Never written

Claude proposes the change in chat instead.

  • composer.json
  • composer.lock
  • package.json
  • vendor/
  • node_modules/
  • data/
  • log/
  • public/uploads/
  • Migration/

Never run

Dependency changes and history rewrites stay a human decision.

  • composer require
  • composer update
  • npm/yarn/pnpm install
  • git push
  • git reset --hard
  • git clean
  • rm -rf

Asks first

Reachable, but never silently.

  • doctrine-migrations
  • bin/cli.php
  • mysql
  • git commit
  • git add
  • config/pipeline.php
  • phpstan.neon
  • .github/
  • CHANGELOG.md

Runs freely

The quality gate and read-only git, so a review or a fix doesn't stall on prompts.

  • composer check
  • cs-check
  • cs-fix
  • static-analysis
  • test
  • clear-config-cache
  • dump-autoload
  • vendor/bin/*
  • php -l
  • git status
  • git diff
  • git log

The ask and allow tiers are preference — override them per machine in settings.local.json, which is git-ignored, never in the shared file.

Ten commands for the work that repeats

Each one is a checklist Claude follows rather than a prompt you retype.

/dk-bootstrapFresh clone to a running install.
/dk-modulePlan a new module — dot-maker first, manual wiring after.
/dk-routeAdd a fully wired endpoint or page.
/dk-traceFollow a request through pipeline, handler and response.
/dk-testWrite and run unit or functional tests.
/dk-documentWrite the feature doc a cleared session cannot reconstruct from src/.
/dk-checkRun the QA gate and fix what it reports.
/dk-deprecateA breaking change the evolution-pattern way — sunset headers, not versions.
/dk-reviewPre-PR convention review. Read-only by design.
/dk-hygieneEncoding and line-ending audit.

Seventeen skills, loaded when the question calls for them

There is no routing table. Each skill's description decides whether it loads, so asking where a new Doctrine entity goes reaches for module structure rather than general framework knowledge.

One of them changes how Claude names packages, and it needs a line in your project's CLAUDE.md to fire reliably: the ladder runs already in composer.lock, then dotkernel/*, then laminas/* and mezzio/*, then a vetted community package, then hand-rolled code. Never a package name from memory.

  • application-variants
  • module-structure
  • handler-naming
  • doctrine-entities
  • input-validation
  • responses
  • openapi
  • feature-docs
  • testing
  • evolution-pattern
  • security
  • dot-maker
  • core-submodule
  • psr-standards
  • qa-gate
  • troubleshooting
  • dependency-policy

Real usage in the status bar

Taken from the rate-limit payload Claude Code passes in on stdin — the same numbers /usage reports. Pure bash and awk, so it works in Git Bash on Windows.

statusline.sh
~/project : Opus 5 ==> 5h:37% 2h14m left, resets @16:20 | 7d 61%

Install

The payload has to sit at the root of your project. Clone it or take the zip — same files either way.

Get .claude/ into the project

The clone is removed straight after the copy, so nothing nested is left for a git add . to trip over. Without git, the zip carries the dotfiles too.

$ cd <project>
$ git clone --depth 1 https://github.com/dotkernel/dotboost.git .dotboost
$ cp -r .dotboost/.claude .claude
$ rm -rf .dotboost

Restore the executable bits

Nothing is committed executable, and a zip extracted on Windows carries no permission bits at all. The hooks and status line are invoked as bash <path> and run regardless; the dependency-policy sync script is called by its own name.

$ chmod +x .claude/hooks/*.sh .claude/statusline.sh \
           .claude/skills/dependency-policy/scripts/*.sh
$ echo '.claude/settings.local.json' >> .git/info/exclude

Paste the dependency policy into CLAUDE.md

A skill description decides whether a skill can load, not whether Claude stops to think before naming a package. That rule has to be always loaded, which means it lives in your project's own CLAUDE.md. The README carries the block to paste.

Read the block on GitHub

Verify

Start Claude Code in the project. /help should list the dk-* commands and the session hook should open with the briefing. Then test a guardrail: ask it to edit vendor/autoload.php, or to add a package to composer.json. Both should be refused, with the change proposed in chat instead.

If the project already has its own .claude/settings.json or commands/, merge by hand — same-named files are overwritten. To update later, run the install again over the top; that is why personal changes belong in settings.local.json.

Treat the skills as living documents

When a review turns up the same mistake twice, that is a missing line in a skill, not a Claude problem. Before adapting dotboost to a new Dotkernel application, spend an hour reading that repo and correcting the skills against what is actually there — a skill written from framework docs rather than the codebase produces confident wrong answers, which is worse than no skill.