Configuration Management Practices for ai-job-search: Defensive Layered Security

The ai-job-search repository implements a defensive, layered configuration management strategy centered on a single source of truth in the .claude/ directory, strict permission whitelisting, and automated CI validation to prevent configuration drift and accidental data leakage.

This open-source project by MadsLorentzen/ai-job-search manages AI agent configurations through a disciplined approach that separates template specifications from personal customizations. Configuration management practices for ai-job-search prioritize security and reproducibility by centralizing runtime settings under version control while blocking unsafe command execution through explicit allow-lists.

Centralized Configuration Architecture

All runtime settings, skill specifications, and command definitions live in a hidden .claude/ directory at the repository root. This thin-pointer design prevents duplication across multiple agent runtimes including Claude Code, Antigravity, and Codex.

The canonical configuration source resides in .claude/settings.json, which acts as the central permission allow-list. Skill and command definitions are stored as markdown files within subdirectories, such as .claude/skills/job-application-assistant/01-candidate-profile.md. This structure ensures that every AI agent instance references identical configuration parameters without maintaining separate copies.

Permission-First Security Model

The repository ships with a minimal permission whitelist that explicitly limits which commands the Claude runtime may invoke. This protects users from accidental execution of unsafe code by enumerating only approved operations rather than relying on broad exclusions.

The "permissions": { "allow": [...] } block in .claude/settings.json restricts execution to specific, vetted scripts:

  • Skill(job-application-assistant)
  • Bash(bun run:*)
  • Bash(python salary_lookup.py:*)
  • Bash(python3 salary_lookup.py:*)
  • Bash(pdftotext:*)

Any attempt to broaden these permissions beyond the predefined set triggers a CI failure before merge.

Automated CI Validation Pipeline

Every push or pull request triggers a multi-job GitHub Actions workflow defined in .github/workflows/ci.yml that enforces configuration integrity through four specialized validation stages.

Lint and Schema Verification

A dedicated Python linter scans the .claude/ tree for malformed skill definitions and missing required fields. The lint job executes tools/lint_skills.py to verify that all markdown skill files conform to the expected schema:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install pyyaml
      - run: python tools/lint_skills.py

Security Guards and Permission Enforcement

The security-guards job runs tools/security_guards.py to verify three critical invariants: the settings.json permission block has not been broadened, the repository's .gitignore protects personal data, and placeholder tokens remain in template files. The script enforces permission limits through explicit set comparison:

import json, sys, pathlib

settings = json.load(open('.claude/settings.json'))
allowed = set(settings['permissions']['allow'])
if not allowed.issubset({
    "Skill(job-application-assistant)",
    "Bash(bun run:*)",
    "Bash(python salary_lookup.py:*)",
    "Bash(python3 salary_lookup.py:*)",
    "Bash(pdftotext:*)"}):
    sys.exit("❌ Unauthorized permission added!")

Dependency and Placeholder Integrity

For upstream pull requests only, the dependency-review job invokes GitHub's official Dependency Review action to flag high-severity vulnerabilities. A separate placeholder-integrity job asserts that template files still contain placeholder markers such as [YOUR_NAME], preventing accidental commits of personal data to the canonical repository.

Upstream Update Management

Users can safely merge upstream changes without overwriting personalized files. The tools/check_upstream_updates.py helper, documented in SETUP.md, diffs the upstream template against the local fork and lists only files that would be affected:

python3 tools/check_upstream_updates.py

Additionally, tools/check_framework_version.py runs exclusively when the repository is the official upstream, ensuring that forks do not unintentionally diverge from the canonical framework version.

Summary

  • Centralized specifications in .claude/settings.json eliminate configuration drift across AI agent runtimes.
  • Explicit permission whitelisting restricts command execution to vetted scripts only, preventing arbitrary code execution.
  • Automated CI gates in .github/workflows/ci.yml catch malformed skills, unauthorized permission changes, and missing placeholders before merge.
  • Security hardening via tools/security_guards.py validates .gitignore protections and placeholder integrity in every pull request.
  • Safe upstream synchronization through tools/check_upstream_updates.py preserves personal customizations when pulling template updates.

Frequently Asked Questions

How does ai-job-search prevent accidental execution of dangerous commands?

The repository uses an explicit allow-list model rather than block-listing. The .claude/settings.json file contains a strict permissions.allow array that enumerates only five approved command patterns. The CI pipeline enforces this list immutably through tools/security_guards.py, which exits with an error if any unauthorized permission is added.

Where should I add new AI skills or commands?

All skill definitions belong in the .claude/ directory, specifically under .claude/skills/. Each skill is a markdown file with a numbered prefix (e.g., 01-candidate-profile.md). The tools/lint_skills.py linter validates these files during CI to ensure they contain required frontmatter fields and valid command references.

How do I update my fork without losing personal data?

Run python3 tools/check_upstream_updates.py before pulling upstream changes. This script compares your local files against the upstream template and identifies which files would be modified, allowing you to preserve personalizations such as filled-in candidate profiles while incorporating template improvements.

What prevents personal information from leaking into the public template?

The placeholder-integrity CI job continuously scans template files for placeholder tokens like [YOUR_NAME]. If these markers are removed (indicating real data has been inserted), the job fails and blocks the merge. Additionally, tools/security_guards.py verifies that .gitignore properly excludes personal data directories.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →