agentleFS
CodesWhatCodesWhat/careerrat/.agents/skills/reevaluate-strategy/SKILL.md

reevaluate-strategy

Skill4 starsChanged 11 days agoMITView on GitHub

Learn from accumulated outcomes — read the funnel, rejections, interview transcripts, and wins, then recommend concrete tuning to targeting signals, comp anchoring, fit calibration, channel mix, and writing-style. Triggered by outcome thresholds or an explicit review request.

The file

Show its rules and text

We split this skill into the rules it gives an agent

25 rules. About 0 are common, 6 are distinctive, and 19 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈6

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 19

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Run: careerrat analytics refresh --json (dry-run read.

    line 36
  2. Very specific:

    If reevaluation.due is false AND the user did NOT explicitly request a review: report current counts, state "below threshold — no action …

    line 51
  3. Very specific:

    If reevaluation.due is true OR user explicitly requested: continue to STEP 1.

    line 52
  4. Very specific:

    Read workspace/tracker.json.

    line 85
  5. Very specific:

    Read candidate/honesty.yml to cross-check any claimed gaps against confirmed tools and do_not_claim boundaries.

    line 118
  6. Distinctive:

    After completing STEP 4, synthesize STEPS 1–4 into a single structured recommendation block before presenting individual dimension …

    line 132
  7. Very specific:

    Tighten targeting.yml cut-signals: add "<proposed signal string>" to cut_signals.

    line 159
  8. Distinctive:

    If no dimension has N ≥ 3 signal, state: "Insufficient data for high-confidence recommendations (all slices N < 3).

    line 168
  9. Distinctive:

    After the user responds to the STEP 4b recommendation block — accepting all, some, or none — expand each accepted item into its full detail …

    line 172
  10. Very specific:

    Read candidate profile compensation.target_base, compensation.minimum_base, and compensation.current_comp_shareable.

    line 183
  11. Very specific:

    If comp-stage rejections cluster, or warn flags appear on below-floor applications: propose a new target_base or minimum_base value.

    line 184
  12. Very specific:

    PRIVACY INVARIANT: Never read, surface, log, or reference current_base in any output, recommendation, or artifact.

    line 185
  13. Distinctive:

    If high-fit roles (score ≥ high_min from targeting.fit_bands) reject while stretch roles (< med_min) advance, the scoring prior is off.

    line 188
  14. Very specific:

    If transcripts or rejection notes reveal a recurring overclaim or framing gap: propose a concrete change to candidate/writing-style.md (a …

    line 192
  15. Very specific:

    If the user states a new gate mid-flow ("never apply to X", "below $Y is a no", "add Z as a cut signal"), write it through careerrat gate …

    line 204
  16. Very specific:

    Use careerrat gate keep-signal "<signal>" --write or careerrat gate cut-signal "<signal>" --write for accepted signals.

    line 211
  17. Very specific:

    If a comp re-anchor is accepted, use careerrat gate comp-target <N> --write or careerrat gate comp-floor <N> --write.

    line 214
  18. Very specific:

    DB workspaces: never hand-edit workspace/tracker.json.

    line 219
  19. Very specific:

    Run careerrat data verify (DB mode) or careerrat tracker --verify (legacy) immediately after.

    line 232
  20. Very specific:

    If writing/positioning change accepted, edit candidate/writing-style.md with the specific addition/modification.

    line 261
  21. Very specific:

    If candidate/writing-style.md was changed: careerrat lint-placeholders candidate/writing-style.md.

    line 292
  22. Distinctive:

    All steps must pass before declaring the skill complete.

    line 294
  23. Very specific:

    Only when the workspace is still in legacy tracker.json mode (no db yet) does the stamp skip the log.

    line 298
  24. Distinctive:

    Do NOT re-score the whole board silently — every mutation must be traceable to this session's evidence.

    line 315
  25. Very specific:

    Never invent outcomes or transcript content.

    line 318

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

reevaluate-strategy

Use this skill when the user asks why they're getting filtered, to review their strategy, to re-rank sourced roles, or "what should I change" — or when track-outcomes trips a threshold (see the Reevaluation Contract in AGENTS.md). This is the self-tuning half of the loop: it turns accumulated outcomes into concrete, recommended adjustments.

Runs under AGENTS.md. These contracts bind without being restated here: Privacy Invariant (current_base never outbound), Honesty Firewall, Placeholder/Bracket Ban, Gate Write-back, Domain-Neutral Rule, Browser Automation Contract, Activity Pulse logging, Tracker verify+snapshot, and Sent-Clears-Draft. Inline reminders at point-of-use are intentional; standalone restatements point back to the relevant AGENTS.md section. Bare candidate/, workspace/, config/, and .internal/ paths below are symbolic; resolve them per AGENTS.md's Path Resolution rule.

Agent voice. Read candidate modes through the shared DB-first accessor (modes.agent_voice, default standard) before producing strategy recommendations. Apply the register from AGENTS.md#mode-switches. exec-summary = top 2–3 recommended changes as bullets + threshold that tripped; standard = findings summary + recommendations as scannable bullets; technical = funnel analysis + per-signal breakdown + recommended changes; verbose = full analysis including win/rejection patterns, confidence levels, and proposed gate write-backs.


STEP 0 — GATE CHECK (trigger confirmation)

Trigger sources. This skill is entered either:

  • Explicitly by the user ("why am I getting filtered", "review my strategy", "re-rank prospects", "what should I change").
  • Via handoff from track-outcomes STEP 6, which reads the persisted reevaluation gate at tracker.json#analytics.reevaluation (refreshed by careerrat analytics --write as part of the Tracker Write Contract) and hands off here when reevaluation.due is true — passing reevaluation.dueReasons (the tripped threshold names and counts).

Read the persisted gate; do not recompute the trip. The threshold comparison is already applied by buildReevaluationAnalytics() and stored in tracker.json#analytics.reevaluation — thresholds resolved from candidate targeting config reevaluation.rejection_total / reevaluation.rejection_per_family (defaults: 7 total, 3 per family if absent). This mirrors track-outcomes STEP 6 and the AGENTS.md Tracker Write Contract — read the block, trust reevaluation.due.

Pre-flight: analytics.mjs reads workspace/tracker.json (the source of truth) and resolves it relative to the repo root, so it runs from any cwd — no dashboard render is required first. If the file is missing, seed it: cp templates/tracker.json workspace/tracker.json.

Run: careerrat analytics refresh --json (dry-run read; use -- --write if you also want to persist the refresh to tracker.json#analytics).

The output (from buildReevaluationAnalytics in src/core/tracker/outcome-analysis.mjs) includes:

  • byStatus — counts keyed by status value (e.g. rejected, offer, awaiting, interview).
  • rejected.total / rejected.byFamily — cumulative rejected counts, total and per family slug (slugs derived from role_families → role_buckets → neutral title slug).
  • advanced.total / advanced.byFamily — cumulative interview/offer counts, total and per family slug.
  • reevaluation.thresholds — the resolved trip thresholds (total + per family).
  • reevaluation.sinceLastReview — rejections accumulated since the last strategy-review stamp (rejectionTotal + rejectionByFamily). This delta, not the cumulative total, is what trips the gate — a strategy review stamps a snapshot, so only NEW rejections since then count.
  • reevaluation.due / reevaluation.dueReasons — the trip verdict and the human-readable reasons. Trust this; never re-derive the trip from cumulative rejected.byFamily totals.

(npm run analyze:outcomes — buildOutcomeSummary — is the descriptive funnel breakdown used in STEP 1. Its byRoleFamily is total apps per family, NOT rejected-per-family, and it does not compute the trip. Never read the gate from it.)

Branch:

  • If reevaluation.due is false AND the user did NOT explicitly request a review: report current counts, state "below threshold — no action needed," and exit.
  • If reevaluation.due is true OR user explicitly requested: continue to STEP 1.

Also read application limits now. In DB mode use careerrat data candidate get --json (application-limits.companies[]); in legacy mode read candidate/application-limits.yml. Identify any per-company caps or cooldowns that could be inflating rejection counts — exclude cap-blocked entries from reject-pattern tallies (a cap block is not a strategy signal).


STEP 1 — QUANTITATIVE BASELINE

[DELEGATE: subagent] The read-only analysis phase (STEPS 1–4) parallelizes — the quantitative baseline, funnel tally, qualitative transcript read, and win analysis are independent slices over the same data. Fan out a subagent per slice (each reads tracker.json / transcripts and returns a structured findings block); the orchestrator synthesizes the recommendation in STEP 5 and owns every write (STEPS 6–7: direct with an Undo, except lowering comp). Subagents read only — they never write config, the tracker, or learning files. STEP 0's trigger gate already ran on the orchestrator. Degrade to inline sequential analysis with no subagent primitive. See the Delegation Contract in AGENTS.md.

Run: npm run analyze:outcomes

This produces the full JSON breakdown. Extract the following slices (flag any slice with N < 3 as unreliable / "small-N"):

  • By role-family (byRoleFamily) — counts keyed by the candidate's own family slugs. classifyRoleFamily in outcome-analysis.mjs derives these from candidate targeting config role_families (explicit [{name, patterns[]}]) → role_buckets (bucket name slugified, titles as patterns) → neutral title slug (no config). Do NOT hardcode any domain-specific family names here.
  • By fit-band — buildOutcomeSummary does NOT emit a byFitBand field. Partition rejected applications by the persisted app.fitBucket field (written by evaluate-job at evaluation time, so it reflects the fit_bands thresholds that were in effect when each role was scored — the same bucket the dashboard shows). Do NOT re-derive bands by re-applying current fit_bands to fitScore: thresholds may have moved since these rows were evaluated, and silently re-bucketing the board is the exact consequential re-score STEP 7 gates as confirm-first. Fall back to fitScore + current fit_bands (high_min default 85, med_min default 65 — high ≥ high_min, med ≥ med_min, stretch < med_min) only for the rare row missing fitBucket.
  • By channel (byChannel) — keyed by each application's channel value (e.g. referral, recruiter, board, portal). Cross-filter to rejected-only for reject-rate; cross-filter to offer/interview for advance-rate.
  • By mode (byMode) — keyed by each application's mode value (e.g. remote, hybrid, onsite).
  • By sourced pipeline (sourcedFamilies) — family-slug counts for sourced (not-yet-submitted) prospects; use this to check whether the candidate is feeding the right families into the top of the funnel.

Record: reject-rate and advance-rate for each slice, with N. Slices at small-N get a "(small-N: treat as directional only)" label.


STEP 2 — FUNNEL POSITION TALLY

Read workspace/tracker.json. For each rejected application, inspect conversations[]. The schema defines {date, kind, who, notes, recording} — there is no stage field. Use conversations[].kind (e.g. "resume-screen", "recruiter", "hm", "panel", "offer-comp") to derive funnel position. Use conversations[].notes for stated rejection reasons.

Locate each application row by matching applications[] entries on id, or on company + role if no id exists.

Tally rejection counts by kind value. Name the dominant choke point (the kind value with the most rejections). The fix depends on the stage:

Dominant stageLikely fix direction
resume-screenrésumé copy, keyword alignment, positioning
recruitercomp anchoring, role-fit framing
HM / paneldepth of evidence, overclaim gaps
offer/compcomp floor vs ask gap

STEP 3 — QUALITATIVE SIGNAL

For each affected role-family, check whether this rejection pattern was already logged (avoid surfacing the same recommendation twice if it was already actioned). Read via the CLI:

careerrat learnings read "<role title or family>" --family

(Pass the family slug with --family, or pass a role title without it and the CLI will resolve the slug. If the family has no file yet the CLI prints a note to stderr and exits 0 — a missing file is normal and not an error.)

From conversations[].notes across all rejected applications, identify recurring qualitative themes:

  • Positioning mismatch or framing gap.
  • Suspected overclaims (honesty.yml do_not_claim items mentioned as gaps).
  • Comp rejection (offer-stage or below-floor warn flag set).
  • Keyword miss (role required something not in résumé).
  • Fit overcount (role scored high but rejected early).

Read candidate/honesty.yml to cross-check any claimed gaps against confirmed tools and do_not_claim boundaries. Do not surface a "gap" that honesty.yml lists as do_not_claim — that is expected.


STEP 4 — WIN ANALYSIS

From the same npm run analyze:outcomes output, run the same family/channel/mode/fit-band breakdown on advances and offers only.

Identify where the candidate is advancing. This is the double-down signal — weight it as strongly as the rejection signal. A family/channel that is converting is evidence to prioritize, not noise.


STEP 4b — ADAPTIVE RE-RANK NUDGE (rejection-feedback surface)

After completing STEP 4, synthesize STEPS 1–4 into a single structured recommendation block before presenting individual dimension proposals. This is the rejection-feedback nudge: use accumulated outcomes as evidence to update targeting priorities, not to silently re-score the board.

Small-N rule (explicit): Do NOT auto-apply any adjustment when the supporting evidence is N < 3 for that dimension. Present the recommendation as a suggestion and state the N. Only write it after the user explicitly applies it. This rule applies even when a threshold was tripped. The threshold determines whether to run the analysis; the small-N rule determines how confidently to act on each slice. At N >= 3 the change applies directly (STEP 6) and is logged with an Undo.

Construct the recommendation block as follows:


Strategy Adjustment Recommendation

Trigger: <threshold name that was crossed> — <count> total rejections / <count> in <family-slug> family (or "user-requested review").

Where filtering is occurring:

DimensionSliceRejections (N)Advance/Offer (N)Reject-rateSignal strength
Role-family (byRoleFamily)<slug>NN%reliable / directional
Channel (byChannel)<value>NN%reliable / directional
Mode (byMode)<value>NN%reliable / directional
Fit-band (derived)high / med / stretchNN%reliable / directional
Funnel stage (from conversations[].kind)<kind>N——reliable / directional

(Omit rows where N = 0. Mark N < 3 as "directional".)

Recommended adjustments (one line each; apply-directly vs. confirm-first noted):

  1. Re-rank sourced prospects: <specific family/channel to promote or deprioritize> (affects workspace/tracker.json priority/status fields). N = <N>. [applies directly with an Undo at N >= 3]
  2. Tighten targeting.yml cut-signals: add "<proposed signal string>" to cut_signals. N = <N>. [applies directly with an Undo at N >= 3]
  3. Re-anchor comp: propose new candidate profile compensation.target_base or compensation.minimum_base. [raising applies directly with an Undo; lowering or clearing is confirm-first]
  4. Fit recalibration: <high-fit-rejects pattern>: spot-check with careerrat evaluate on 2–3 rejecting roles, then propose fit_bands or keep_signals tweak. [applies directly with an Undo at N >= 3]
  5. Double-down signal — <family or channel converting>: increase sourcing weight here.

Your call: Accept all / accept some / decline. State which items to apply and I will write them now.


If no dimension has N ≥ 3 signal, state: "Insufficient data for high-confidence recommendations (all slices N < 3). Directional patterns noted above — continue sourcing and re-run when N reaches 3 in the flagged families."

STEP 5 — RECOMMENDATIONS (detailed blocks, on accept)

After the user responds to the STEP 4b recommendation block — accepting all, some, or none — expand each accepted item into its full detail block. For declined items, skip. For items the user defers, note them as pending.

Produce one detailed block per accepted dimension (N ≥ 3 or explicit pattern). Each block must state the supporting N and evidence.

(a) Re-rank sourced roles Name which family/channel to prioritize or deprioritize in workspace/tracker.json (direct edits to the priority or status fields of affected rows). State the before/after for each affected entry.

(b) Signal tuning Propose specific strings to add to candidate targeting keep_signals or cut_signals. One proposed string per evidence line. Do not propose broad category exclusions (e.g., "all companies over 500 employees"). Propose named companies and specific signal strings instead.

(c) Comp re-anchor Read candidate profile compensation.target_base, compensation.minimum_base, and compensation.current_comp_shareable. current_comp_shareable is a read-only gate: if true, current_base may exist in profile but must NEVER appear in any output or recommendation regardless. All outbound comp uses target_base, minimum_base, or expected_base only (see foundations-spec §9). If comp-stage rejections cluster, or warn flags appear on below-floor applications: propose a new target_base or minimum_base value. PRIVACY INVARIANT: Never read, surface, log, or reference current_base in any output, recommendation, or artifact. Use only target_base, minimum_base, and expected_base.

(d) Fit recalibration If high-fit roles (score ≥ high_min from targeting.fit_bands) reject while stretch roles (< med_min) advance, the scoring prior is off. Spot-check: run careerrat evaluate <path-to-job.md> on a sample of 2–3 of the rejecting high-fit roles to see what would re-score them to med. Propose a targeted keep_signals or fit_bands threshold adjustment based on what those runs show. Do not silently re-score the whole board.

(e) Writing/positioning adjustment If transcripts or rejection notes reveal a recurring overclaim or framing gap: propose a concrete change to candidate/writing-style.md (a specific line or section to add/modify, not vague advice). Note that npm run calibrate:style must run if new writing samples were added to workspace/writing-samples/.


STEP 6 — APPLY, LOG, AND SUGGEST

Present all recommendations together as a numbered list with evidence for each, and say how many data points back each one.

Apply directly, with an Undo: every recommendation with N >= 3 supporting data points applies through the owning DB-aware writer (cut and keep signals, excluded companies, per-company caps and cooldowns, fit_bands, re-ranks of any size, a raised comp floor or target) and is logged so the user can undo it. A new learning entry is written and logged too, but a learning is append-only, so it can't be undone. Echo the CLI confirmation for each write.

Still confirm-first: lowering the comp floor or target, and any recommendation with fewer than 3 supporting data points. The thin-evidence ones are logged as suggestions only. Propose the exact change and get an explicit user yes before writing.

If the user states a new gate mid-flow ("never apply to X", "below $Y is a no", "add Z as a cut signal"), write it through careerrat gate immediately (a comp drop stays confirm-first). A stated gate must never live only in chat.


STEP 7 — WRITE-BACK (on accept)

(a) Targeting signal changes Use careerrat gate keep-signal "<signal>" --write or careerrat gate cut-signal "<signal>" --write for accepted signals. For fit-band threshold changes, use careerrat data candidate patch targeting --data ... in DB mode; legacy YAML is fallback only when no DB exists. Run careerrat doctor.

(b) Profile comp re-anchor If a comp re-anchor is accepted, use careerrat gate comp-target <N> --write or careerrat gate comp-floor <N> --write. Raising one writes directly. Lowering or clearing one needs the user's yes first, then add --confirm. Do NOT touch compensation.current_base — it is a private gate input, not an output.

(c) Re-rank write-back

DB workspaces: never hand-edit workspace/tracker.json. Apply each accepted re-rank through the owning verbs — careerrat data app set-status for status changes, careerrat data app set-fields for priority and the followUp clears, careerrat data comm upsert / comm append-message for the comm-side clears and the note (careerrat data --help for exact syntax).

Legacy workspaces: edit workspace/tracker.json directly for any accepted re-rank changes (update priority or status fields on the affected rows).

CTA clear (same write — no ghost CTAs): For every row whose status changes to deprioritized or any terminal/inactive state (e.g. withdrawn, dropped, closed), in the same write also:

  • Set followUp.due → null and followUp.draft → null (if the keys exist).
  • Set comm.nextActionDue → null and comm.draft → null (if the keys exist).
  • Rewrite comm.nextAction → "" or remove the key.
  • Append a note entry to comm.messages[]: { "date": "<YYYY-MM-DD>", "kind": "note", "actor": "agent", "body": "Row deprioritized via strategy review — outreach paused." } — this preserves history and self-clears the CTA.

Echo the cleared fields for each affected row: Cleared CTAs on <company>/<role>: followUp.due, comm.nextActionDue, comm.draft → null; note appended.

Run careerrat data verify (DB mode) or careerrat tracker --verify (legacy) immediately after.

(d) learnings/<family>.md — append dated entry For each affected role-family, compose the entry body as markdown using this template:

- **Pattern:** <1-2 sentence summary of what the data shows>
- **Evidence:** <app-id or company name citations from tracker.json>
- **Recommendation applied:** <exact change made — e.g. "Added 'no headcount' to cut_signals">
- **Advance signal:** <win patterns from same family, if any>

The ## <ISO-DATE> — <label> heading is produced by the CLI (--title / --date); the body passed is the bullet block above only. Write the body to a temp file, then:

  1. Dry-run (lints for placeholders and comp leaks):

    careerrat learnings append "<role title or family>" --title "<short pattern label>" --body-file <path-to-temp-file>
  2. Commit on success:

    careerrat learnings append "<role title or family>" --title "<short pattern label>" --body-file <path-to-temp-file> --write

Pass --family if providing an explicit slug rather than a role title. Pass --date YYYY-MM-DD to override today's date. The CLI derives the family slug from candidate targeting config and creates candidate/learnings/ and the file on first --write.

(e) writing-style.md If writing/positioning change accepted, edit candidate/writing-style.md with the specific addition/modification. If new writing samples were added, run npm run calibrate:style.

(f) tracker.json — stamp the review marker (ALWAYS, even on a no-change review) A completed review must clear the dashboard "review ready" nudge whether or not any adjustment was accepted — running the analysis is the review. Stamp the marker:

careerrat strategy-review stamp --write

This records tracker.json#strategyReview = { lastReviewedAt, snapshot: { applied, advanced, rejected, outcomes } }, where outcomes (all-time advances + rejections) is the count the render gate compares the live total against. The banner stays quiet until the funnel produces enough NEW outcomes (default 5) — or a slow drip ages past the cooldown (default 21 days). Dry-run without --write to preview. The marker is mechanical (timestamp + outcome snapshot); this skill still owns the strategy judgement. Without this stamp the nudge re-fires on every render forever, since the rolling 30-day counts stay above threshold regardless of whether a review just ran.


STEP 8 — VALIDATE AND SNAPSHOT

Orphaned-CTA check (before render): After stamping the strategy-review marker and before snapshotting, run a targeted check over every row whose priority or status was changed in STEP 7(c). For each such row, confirm in workspace/tracker.json that no comm.nextActionDue or followUp.due remains set on a row that is now in a dormant/inactive state. If --verify output flags orphaned due-dates on re-ranked rows, null them now and re-run verify before proceeding.

Run in sequence:

  1. careerrat tracker --verify — schema check passes with zero errors.
  2. npm run verify:tracker — tracker integrity check (foundations-spec §6, distinct from schema check above).
  3. careerrat tracker — create a deduplicated recovery checkpoint under workspace/.snapshots/; the source write itself refreshes the live app.
  4. careerrat lint-placeholders candidate/learnings/ — belt-and-suspenders final sweep for placeholder strings in learning files. (careerrat learnings append already lints each entry on write; this is a backstop for the whole directory.)
  5. If candidate/writing-style.md was changed: careerrat lint-placeholders candidate/writing-style.md.

All steps must pass before declaring the skill complete.

Activity Pulse logging: in DB mode, STEP 7(f)'s strategy-review stamp --write already logs the "Strategy review" event itself — do NOT append a second one. Only when the workspace is still in legacy tracker.json mode (no db yet) does the stamp skip the log; in that case, and only then, log it manually (see Activity Pulse in AGENTS.md):

careerrat activity append --type system --actor agent \
  --title "Strategy review" --summary "<what changed and why>" --write

STEP 9 — CLOSE

State what changed, why, and which specific evidence drove each change (cite the N and the stage or note that motivated it). Keep it auditable.

Rules:

  • Do NOT re-score the whole board silently — every mutation must be traceable to this session's evidence.
  • Learn from wins as strongly as rejections — double down on what is converting.
  • Hand drafting (follow-ups, withdrawals, recruiter outreach triggered by this review) to email-comms. This skill decides what to change, not the outreach itself.
  • Never invent outcomes or transcript content; use only what is recorded in workspace/tracker.json and candidate/learnings/.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.