diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..6434985 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,19 @@ +--- +framework_version: 1.0.0 +--- + +# Agent Guidelines: AI Job Search + +This workspace is structured to manage job search activities, scraper tools, CVs, cover letters, and interview preparation. + +## Thin-Pointer Design (Single Source of Truth) + +To prevent duplication and configuration drift across different AI agent frameworks (Claude Code, Google Antigravity, Codex, Cursor, Gemini CLI, etc.), this workspace uses a unified thin-pointer design. All agent runtimes should load the canonical specifications and candidate profiles from the files and directories below: + +1. **Personal Candidate Profile:** + - The candidate profile, contact details, education, and target preferences are defined in [CLAUDE.md](CLAUDE.md) and the individual profile methodology files under [.claude/skills/job-application-assistant/](.claude/skills/job-application-assistant/) (specifically `01-*.md` etc.). +2. **Canonical Workflow Specifications:** + - The step-by-step instructions and triggers for tasks (setup, scrape, rank, apply, upskill, interview) are defined in the [.claude/](.claude/) directory (specifically under `.claude/skills/` and `.claude/commands/`). + - Do not duplicate these rules or specifications. Treat `.claude/` files as the single source of truth. +3. **Portal Search Skills:** + - Job-portal search CLIs live under [.agents/skills/](.agents/skills/) in the portable Agent Skills format (with a `SKILL.md` per portal). Codex and Antigravity discover these automatically; the `/scrape` workflow in [.claude/skills/job-scraper/](.claude/skills/job-scraper/) orchestrates them. diff --git a/tools/check_framework_version.py b/tools/check_framework_version.py index e532268..cfdea06 100755 --- a/tools/check_framework_version.py +++ b/tools/check_framework_version.py @@ -17,6 +17,11 @@ ROOT = Path(__file__).resolve().parent.parent SKILL_DIR = ROOT / ".claude/skills/job-application-assistant" FRAMEWORK_FILES = sorted(SKILL_DIR.glob("*.md")) +# Add root AGENTS.md if it exists +root_agents = ROOT / "AGENTS.md" +if root_agents.exists(): + FRAMEWORK_FILES.append(root_agents) + def run_git(args: list[str]) -> tuple[int, str, str]: res = subprocess.run(["git"] + args, cwd=str(ROOT), capture_output=True, text=True) return res.returncode, res.stdout, res.stderr diff --git a/tools/check_upstream_updates.py b/tools/check_upstream_updates.py index 7a816e5..483f7e3 100755 --- a/tools/check_upstream_updates.py +++ b/tools/check_upstream_updates.py @@ -20,16 +20,16 @@ import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent -SKILL_DIR = ".claude/skills/job-application-assistant" FRAMEWORK_FILES = [ - "01-candidate-profile.md", - "02-behavioral-profile.md", - "03-writing-style.md", - "04-job-evaluation.md", - "05-cv-templates.md", - "06-cover-letter-templates.md", - "07-interview-prep.md", - "SKILL.md", + ".claude/skills/job-application-assistant/01-candidate-profile.md", + ".claude/skills/job-application-assistant/02-behavioral-profile.md", + ".claude/skills/job-application-assistant/03-writing-style.md", + ".claude/skills/job-application-assistant/04-job-evaluation.md", + ".claude/skills/job-application-assistant/05-cv-templates.md", + ".claude/skills/job-application-assistant/06-cover-letter-templates.md", + ".claude/skills/job-application-assistant/07-interview-prep.md", + ".claude/skills/job-application-assistant/SKILL.md", + "AGENTS.md", ] def run_git(args: list[str]) -> tuple[int, str, str]: @@ -94,10 +94,10 @@ def main() -> int: updates_available = [] errors = [] - for filename in FRAMEWORK_FILES: - local_path = ROOT / SKILL_DIR / filename + for rel_path in FRAMEWORK_FILES: + local_path = ROOT / rel_path if not local_path.exists(): - print(f"Local file missing: {SKILL_DIR}/{filename}") + print(f"Local file missing: {rel_path}") continue # Get local version @@ -105,7 +105,7 @@ def main() -> int: local_ver = get_framework_version_from_text(local_text) # Get upstream version - rc, upstream_text, _ = run_git(["show", f"{ref}:{SKILL_DIR}/{filename}"]) + rc, upstream_text, _ = run_git(["show", f"{ref}:{rel_path}"]) if rc != 0: # File might not exist upstream yet continue @@ -113,19 +113,20 @@ def main() -> int: upstream_ver = get_framework_version_from_text(upstream_text) if not local_ver: - errors.append(f"Local file {filename} is missing 'framework_version' in frontmatter.") + errors.append(f"Local file {rel_path} is missing 'framework_version' in frontmatter.") continue if not upstream_ver: continue if parse_semver(upstream_ver) > parse_semver(local_ver): updates_available.append({ - "filename": filename, + "filename": Path(rel_path).name, "local": local_ver, "upstream": upstream_ver, - "path": f"{SKILL_DIR}/{filename}" + "path": rel_path }) + if errors: print("Configuration errors:") for err in errors: