From ccfg-core
This skill should be used for ALL coding tasks, code reviews, planning, git operations, and development work. It defines mandatory workflow rules that must be followed in every session.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ccfg-core:workflow-rulesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill defines mandatory workflow rules that must be followed in every development session.
This skill defines mandatory workflow rules that must be followed in every development session. These rules prevent recurring friction patterns discovered across 275 sessions: 42 wrong approaches, 34 buggy code incidents, 27 rejected actions.
Always run pre-commit/lefthook checks before considering any task complete. If the project has pre-commit hooks, lefthook, or other automated checks configured, they must pass before you can close a task or create a commit.
Do not suppress linter warnings, formatter checks, or static analysis findings. Always attempt to fix the root cause first. Suppression hides problems and creates technical debt.
Inline suppression patterns (do not use without exhausting alternatives):
eslint-disable, eslint-disable-next-line, @ts-ignore,
@ts-expect-error, @ts-nocheck, // prettier-ignore# noqa, # type: ignore, # pylint: disable, # nosec#[allow(...)] (blanket forms like dead_code, clippy::all, unused)//nolint, _ = err (silencing errors is suppression)@SuppressWarnings, @SuppressFBWarnings#pragma warning disable, [SuppressMessage], adding to <NoWarn># shellcheck disable=SC##### pragma: no cover, /* istanbul ignore */, skipcqConfig-level bypasses are equally prohibited. Do not work around findings by:
.eslintrc, ruff.toml,
.golangci.yml, pyproject.toml, etc.)Fix root causes — examples:
# WRONG: Suppress complexity warning
def process(items): # noqa: C901
if a:
if b:
if c:
...
# RIGHT: Refactor to reduce complexity
def process(items):
if not _should_process(items):
return
validated = _validate(items)
return _apply(validated)
// WRONG: Ignore the type error
// @ts-ignore
const result: number = fetchData();
// RIGHT: Handle the type properly
const data: unknown = fetchData();
const result = typeof data === 'number' ? data : 0;
// WRONG: Silence the error
result, _ := doSomething()
// RIGHT: Handle or propagate
result, err := doSomething()
if err != nil {
return fmt.Errorf("doSomething: %w", err)
}
Common fixes by violation type:
When suppression is acceptable: If you have genuinely attempted to fix the root cause and the finding is a false positive, a tooling bug, or a third-party code boundary that cannot be changed, targeted suppression is acceptable under these conditions:
Validate markdown files with markdownlint before committing. Common issues to watch for:
[text](url) instead of bare URLsCheck the project's .markdownlint.json or .markdownlintrc for specific rule configurations.
Never use magic numbers. Define constants with descriptive names:
# Bad
if user.age >= 18:
grant_access()
# Good
MINIMUM_AGE_FOR_ACCESS = 18
if user.age >= MINIMUM_AGE_FOR_ACCESS:
grant_access()
Always handle errors explicitly. No shortcuts:
_ = err — always handle or propagate errorsexcept: — catch specific exceptions// Bad
result, _ := doSomething()
// Good
result, err := doSomething()
if err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
Prefer descriptive variable names over abbreviations:
userRepository over urmaxConnectionTimeout over mctcustomerList over clExceptions: well-known abbreviations (i, j, k in loops; err for errors; ctx for context)
Write self-documenting code; only add comments where logic isn't self-evident. Good code reads like prose. Comments should explain "why", not "what":
// Bad
// Increment counter
counter++;
// Good
// Skip first iteration to avoid off-by-one error in legacy API
counter++;
Don't add docstrings, comments, or type annotations to code you didn't change. If you're fixing a bug in a function, don't add docstrings as "while you're there" work unless explicitly asked. Stay focused on the task.
Avoid over-engineering: only make changes directly requested or clearly necessary. Don't add features "just in case" or "for future extensibility" unless the user explicitly asks for it.
Don't add error handling for scenarios that can't happen:
# Bad - file is already validated before this function
def process_user(user_id: int):
if user_id is None: # Can't happen - type system prevents it
raise ValueError("user_id cannot be None")
Don't create abstractions for one-time operations. If something is used once, inline it. Only abstract when you have 2-3 concrete examples showing the pattern.
Never push to main directly. Always create a feature branch and open a PR. This applies even
for documentation changes, typo fixes, or "quick" changes. The PR process exists for a reason.
Ask which branch to target if unclear. Different projects use different conventions:
main or master for productiondevelop for integrationstaging for pre-productionNever assume. Ask: "Which branch should I target for this PR?"
One task = one commit. Do not batch unrelated changes. If you're working on multiple tasks, commit each one separately:
Commit before closing/completing any task. Work is not done until it's committed. The sequence must always be:
git add <file1> <file2>Use conventional commit format: type(scope): description
Types:
feat: New featurefix: Bug fixdocs: Documentation only changesstyle: Formatting, missing semicolons, etc (no code change)refactor: Code change that neither fixes a bug nor adds a featureperf: Performance improvementtest: Adding or updating testschore: Maintenance tasks, dependency updatesci: CI/CD pipeline changesbuild: Build system or external dependency changesScope: The affected component, module, or area (e.g., auth, api, ui, db)
Description: Imperative mood, lowercase, no period at end
Examples:
feat(api): add user profile endpointfix(auth): prevent token expiry race conditiondocs(readme): update installation instructionsrefactor(db): extract query builder to separate moduleNever use git push --force to main/master. Force pushing overwrites history and can destroy
other people's work. If you need to force push to a feature branch, use --force-with-lease which
is safer.
Never use git reset --hard without explicit user approval. This destroys uncommitted work
permanently. Always ask first.
Never skip hooks (--no-verify) unless the user explicitly requests it. Pre-commit hooks exist to catch problems before they enter the history. Bypassing them defeats the purpose.
Always create NEW commits rather than amending, unless explicitly requested. When a pre-commit
hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may
result in destroying work or losing previous changes. Instead, after hook failure:
When staging files, prefer adding specific files by name rather than git add -A. This prevents
accidentally committing:
Example:
# Bad
git add -A
# Good
git add src/auth/login.ts src/auth/login.test.ts docs/auth.md
Use --parent (not --epic) for sub-tasks. The correct flag for creating child tasks is
--parent:
# Correct
bd add "Implement user login" --parent 42
# Incorrect
bd add "Implement user login" --epic 42
Add tasks as children, not blockers, unless explicitly asked. If task B depends on task A, make B a child of A. Only use blockers when the relationship is cross-epic or explicitly requested.
Always commit before closing/completing a task. The sequence must be:
bd close <id> --reason="..."Work on one task at a time unless explicitly told to parallelize. Complete each task fully before moving to the next:
Complete each task fully before the next. "Fully" means:
Don't leave tasks in a half-done state to move to something else unless blocked.
Use bd close <id> --reason="..." to document what was done. The reason should be a concise
summary of what was accomplished, not just "done" or "completed":
# Bad
bd close 42 --reason="done"
# Good
bd close 42 --reason="implemented JWT auth with refresh tokens, added tests, updated API docs"
Run bd sync at end of every session. This ensures your local beads state is synchronized with
the remote issue tracker (GitHub, Jira, Linear, etc.).
Check bd ready for available work, not bd list. The bd ready command shows tasks that are
actually ready to work on (not blocked, in correct status). Use bd list only when you need to see
all tasks regardless of status.
When planning, be concise and action-oriented. Present what you have promptly. Don't spend paragraphs explaining what you're about to do. Instead:
Users prefer seeing progress over reading lengthy explanations.
Do not modify code when asked to update documentation only, and vice versa. Respect the scope:
Don't bundle unrelated changes without asking first.
If scope is unclear, ask before expanding beyond the stated request. When a user says "fix the auth bug", don't also refactor the auth module, update dependencies, and add new features. Fix the bug. Then ask if they want additional improvements.
Present options when multiple valid approaches exist; don't assume. If there are trade-offs, present them:
"There are two approaches:
Which would you prefer?"
Don't pick one silently and hope it's what they wanted.
If blocked, explain why and suggest alternatives rather than silently giving up. When you encounter a blocker:
Example: "I can't proceed with the database migration because the production credentials aren't in the .env file. Options: 1) You provide the credentials, 2) I create a mock environment for testing, 3) I document the migration steps for you to run manually. Which would you prefer?"
Never say "ready to push when you are" — YOU must push. The AI agent is responsible for completing the git workflow. Saying "ready to push" is passing the buck. Just push.
Work is NOT complete until git push succeeds. A local commit is not done. The sequence must
be:
git commit -m "..."git pushAlways verify: git status should show "up to date with origin" at session end. Before ending any
session, run git status and confirm:
If there are unpushed commits, push them unless explicitly told not to.
Never commit files containing secrets (.env, credentials.json, private keys). Before every commit, scan staged files for:
If you need to commit example configurations, use placeholder values:
# .env.example (safe to commit)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
API_KEY=your_api_key_here
# .env (NEVER commit)
DATABASE_URL=postgresql://prod_user:actual_password@prod.example.com:5432/production_db
API_KEY=sk_live_actual_key_12345
Scan for hardcoded credentials before every commit. Use regex or manual review to catch:
password = "actual_password"api_key = "sk_live_..."token = "ghp_..."Never add chmod 777 or world-writable permissions. This makes files readable, writable, and
executable by everyone, which is a security risk. Instead:
chmod 644 for regular files (owner can write, others can read)chmod 755 for executables (owner can write, everyone can execute)chmod 600 for sensitive files (owner only)Never pipe remote content to shell (curl|sh, wget|bash). This pattern downloads and immediately executes remote code without inspection:
# Dangerous
curl https://example.com/install.sh | sh
# Safe
curl -O https://example.com/install.sh
# Inspect install.sh
sh install.sh
Validate all user input at system boundaries. Any data entering the system from:
Must be validated, sanitized, or parameterized before use:
# Bad - SQL injection risk
query = f"SELECT * FROM users WHERE username = '{username}'"
# Good - parameterized query
query = "SELECT * FROM users WHERE username = ?"
cursor.execute(query, (username,))
When reviewing code (either your own before committing, or someone else's PR), use severity levels to categorize feedback:
Correctness:
Security:
Performance:
Maintainability:
Conventions:
Focus on substance over style for things the linter handles. If the project has automated linting for formatting, don't comment on:
The linter will catch these. Focus your review on logic, architecture, and maintainability.
These workflow rules exist because they solve real problems that occurred in hundreds of sessions. Following them prevents:
Every rule has a reason. Trust the process.
npx claudepluginhub jsamuelsen11/claude-config --plugin ccfg-coreManages Git commit workflow using Conventional Commits format with safety protocols. Creates, validates, executes commits; handles hooks, PRs, and safety checks before operations.
Reviews and verifies code before merge via triage-first checks (up to 16 parallel agents). Pipeline mode verifies vs plans; general mode for PRs/branches/staged changes. Flags findings only.
Structures git workflow practices for committing, branching, resolving conflicts, and organizing work across parallel streams. Use when making any code change.