# Private keys
*.pem

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
.*
!.gitignore
!.env.example
!.github
!.claude
!.claudeignore
!.mcp.json
!.cursorignore
!.graph8/
!.graph8/rules/
!.graph8/rules/*.md
!.codex/
!.codex/*.md
!.agents/
!/AGENTS.md
!frontend/.*
!voice/.*
!website/.*
# work-app/ (the graph8 Work app, imported from graph8-com/g8-work) ships
# dotfiles BELOW its top level too — Flutter's apps/work-mobile/.metadata and
# services/work-gateway/.dev.vars.example. The bare `.*` on line 8 matches at
# any depth, so a depth-1-only escape like the three above is not enough.
# Secrets stay ignored via work-app/.gitignore (`.env*`, `.dev.vars`,
# `.dev.vars.*`, `.wrangler/`, `.g8-work-runner.json`), which is deeper and
# therefore wins over these negations. Those patterns are prefix globs on
# purpose — this negation makes work-app/.gitignore the ONLY guard, so it must
# not enumerate variants. Verify with:
#   git check-ignore -v --no-index work-app/.env.production
!work-app/.*
!work-app/**/.*
#
# The rest of this file was written for the Python backend at the repo root,
# and a pattern with no leading slash matches at EVERY depth — including inside
# work-app/. Each such pattern has been classified once:
#
#   ANCHORED (repo-root artifact/scratch that must not reach into work-app/,
#   frontend/ or voice/): /UI/, /searchapi-node/, /cloudflare-worker/,
#   /searchapi/, /*2025-08*.sql, /setup_waterfall_table.py, /test.py,
#   /sample.html, /docker-compose*.yml, /init-db.sh, /auto_create_sequence.py,
#   /celerybeat-schedule*, /memory/, /output/, /.arlink-reference/
#
#   LEFT UNANCHORED ON PURPOSE (genuinely repo-wide, and work-app/.gitignore
#   agrees with every one of them): *.pem, __pycache__/, *.py[cod], *$py.class,
#   dist/, *.egg-info/, *node_modules*, the OS-junk block (.DS_Store, ._*,
#   Thumbs.db, …), CLAUDE.local.md, **/.playwright-cli/
#
# If you add a pattern below, anchor it with a leading `/` unless you mean it
# to apply to work-app/, frontend/ and voice/ as well.

# Build / dist artifacts.
# `/UI/` is ANCHORED: without the leading slash it matched a directory named
# `UI` (and, with core.ignorecase=true on macOS, `ui`) at ANY depth — which
# silently swallowed new files under frontend/components/ui/ and would swallow
# work-app/apps/work-web/src/**/ui/. The tracked files there survive only
# because tracked files ignore .gitignore. It only ever meant the repo-root
# build artifact, so anchor it and say so.
/UI/
# Belt-and-braces now that /UI/ is anchored: frontend/e2e/ui is the testDir for
# the `ui` Playwright project, NOT a build artifact, and must never be ignored.
!frontend/e2e/ui/
!frontend/e2e/ui/**
dist/
*.egg-info/

# Node.js and worker directories. Anchored — these are repo-root legacy
# directories; unanchored they would also match e.g. a future
# work-app/services/cloudflare-worker/.
/searchapi-node/
/cloudflare-worker/
/searchapi/

# Documentation files (except README.md files and campaign_builder docs)
# Only ignore .md files at backend root, not in frontend/ or voice/
/*.md
!/README.md
!/CLAUDE.md
!/AGENTS.md
!/docs/*.md
!/campaign_builder/**/*.md
!frontend/**/*.md
!voice/**/*.md
!website/**/*.md

# Node.js dependencies
*node_modules*

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# local testing files.
# All anchored with a leading `/`: these name specific scratch files that live
# at the BACKEND ROOT. Unanchored they matched at any depth, so a legitimate
# `work-app/services/work-gateway/docker-compose.yml` or any nested `test.py`
# would have been silently un-addable.

/*2025-08*.sql
/setup_waterfall_table.py
/test.py
/sample.html
/docker-compose*.yml
/init-db.sh
/auto_create_sequence.py
sequencer/routers/scripts/*
sequencer/scripts/*
!sequencer/scripts/remove_contact_from_sequence.py

/crm-integration-clone/
# /integrations_v4/
/venv/
/*scripts
!/scripts/
scripts/*
!/scripts/db_connect.py
!/scripts/validate.sh
!/scripts/deliverability-report.py
!/scripts/docs_autodraft_gate.py
!/scripts/prd_workflow.py
!/scripts/backfill_roam_transcripts.py
!/scripts/repair_deal_activity_linkage.py
!/scripts/okf_shadow_backfill.py
!/scripts/requeue_salesforce_call_artifact_http400.py
!/scripts/okf_fleet_rollout.py
!/scripts/dev-foundation/

# Generated developer contract bundle (WP1). ~3.8MB / 493 files, rebuilt from
# source by scripts/dev-foundation/build_contract_bundle.py and published as a
# CI artifact per release candidate. Committing it would add a 4MB diff to every
# route change. The small, hand-reviewable part of the contract IS committed:
# developer_api/openapi_operation_ids.json (the frozen public operationIds).
/developer-contract/*
# The Arazzo blueprint (M4-7) is a hand-authored SOURCE artifact, not a
# generated bundle - track it, and keep it co-located with the openapi.json it
# references so its `./openapi.json` sourceDescription resolves. Everything else
# under developer-contract/ stays generated + ignored.
!/developer-contract/signal-to-qualified-meeting.arazzo.yaml
!/scripts/seed_team_command_center.py
!/scripts/backfill_inbox_thread_split.py
!/marketplace/scripts/reissue_marketplace_payout.py
!/scripts/configure_role_leaderboards.py
!/scripts/seed_org_agents.py
!/scripts/materialize_jobs_indexes.py
!/scripts/verify_inbox_tracing.py
!/scripts/verify_quote_dto_prod.sh
!/scripts/agent_runtime/
!/scripts/agent_runtime/*.py
!/scripts/desk/
!/scripts/desk/*.py
!/scripts/backfill_appointments_to_calendar_events.py
!/scripts/backfill_entity_task_meeting_refs.py
!/scripts/backfill_action_items_to_tasks.py
!/marketplace/scripts/backfill_marketplace_contact_mirror.py
!/scripts/cleanup_meeting_task_descriptions.py
!/scripts/test_roam_import.py
!/scripts/test_roam_webhook.py
!/scripts/register_unipile_whatsapp_webhook.py
!/scripts/hard_copy_sequence.py
!/scripts/sequence_projection.py
!/scripts/backfill_join_link_contacts.py
!/scripts/generate_archetypes.py
!/marketplace/scripts/marketplace_setup_project39.sh
!/scripts/setup_layouts.sh
!/scripts/backfill_archetype_slots.py
!/marketplace/scripts/backfill_sdr_payout_accounts.py
!/marketplace/scripts/cleanup_marketplace_operator_role.py
!/scripts/local_cdp/
!/scripts/local_cdp/**
scripts/local_cdp/dumps/
scripts/local_cdp/__pycache__/
!/scripts/audit_stale_issues.py
!/scripts/seed_time_objection_tag.py
!/scripts/set_warmup_ai_can_apply.py
!/marketplace/scripts/wise_sandbox_smoke.py
!/scripts/backfill_visitor_audiences.py
!/scripts/backfill_cb_deal_stage_history.py
!/scripts/backfill_cb_activities_owner_id.py
!/scripts/backfill_agency_client_mashup_companies.py
!/scripts/unpoison_ai_inbox_event_id.py
!/scripts/audit_meeting_counts.py
!/marketplace/scripts/backfill_marketplace_line_items.py
!/marketplace/scripts/backfill_marketplace_pending_acks.py
!/marketplace/scripts/backfill_marketplace_contract_envelopes.py
!/marketplace/scripts/backfill_marketplace_client_terms_acceptance.py
/sequencer/*scripts
!sequencer/scripts/remove_contact_from_sequence.py
# Log files
logs/*

# Celery. Anchored — celerybeat writes its schedule at the backend root.
/celerybeat-schedule
/celerybeat-schedule.*

# Local memory system (Claude Code's per-machine memory store), which is
# written to the repo root. ANCHORED: unanchored, `memory/` matched a directory
# named `memory` at any depth, which is why `agent_runtime/memory/` needed a
# negation and why new files under `campaign_builder/memory/` or
# `work-app/**/memory/` would have been silently un-addable.
/memory/
# Kept as belt-and-braces: agent_runtime/memory/ is the tracked Python module
# for agent runtime memory and must never be ignored.
!agent_runtime/memory/
CLAUDE.local.md
.claude/agent-memory-local/
.claude/current-work.json
.claude/MEMORY.md
.claude/*.md
!.claude/commands/*.md
!.claude/skills/**/*.md

# Debug screenshots and temp files
/*.png
/*.txt
!README.txt

# Frontend local agent memory
frontend/.claude/

# Claude Flow generated files
.claude/helpers/
.claude/commands/claude-flow-*.md
.claude/commands/analysis/
.claude/commands/automation/
.claude/commands/github/
.claude/commands/hooks/
.claude/commands/monitoring/
.claude/commands/optimization/
.claude/commands/sparc/
.claude/skills/agentdb-*/
.claude/skills/browser/
.claude/skills/github-*/
.claude/skills/hooks-*/
.claude/skills/pair-programming/
.claude/skills/reasoningbank-*/
.claude/skills/skill-builder/
.claude/skills/sparc-methodology/
.claude/skills/stream-chain/
.claude/skills/swarm-*/
.claude/skills/v3-*/
.claude/skills/verification-quality/

# Runtime logs and artifacts (auto-generated)
.codex/logs/
frontend/logs/
# The `logs/*` entry under "# Log files" above contains a slash, so git anchors
# it to the repo root and it does NOT cover nested log dirs. That is why
# frontend/logs/ is listed separately, and why mcp_server/logs/ needs its own
# entry: running the mcp_server suite creates mcp_server/logs/ai_<date>.log,
# which was showing up as an untracked file and would have been committed by a
# careless `git add -A`.
mcp_server/logs/
# Anchored — the auto-generated artifact dir is at the repo root. Unanchored,
# `output/` matched any directory named `output` at any depth, so new files
# under the tracked website/output/ and trends/output/ (and any future
# work-app/**/output/) could not be added.
/output/
website/.playwright-cli/


# playwright-cli scratch (created per-cwd)
**/.playwright-cli/

# Octa cockpit hook state — counter for the heartbeat-tick hook
.claude/state/
!/marketplace/scripts/recovery_marketplace_pipeline.py
!/scripts/unstick_orphan_warmup_mailboxes.py
!/scripts/cancel_inactive_mailboxes.py
!/scripts/pm-review-digest.py
!/scripts/story_probe_health.py
!/scripts/story_fix_dispatch.py
!/scripts/backfill_inboxkit_workspace_index.py
!/scripts/backfill_ms_app_only_consent.py
!/scripts/dedupe_enrichment_configs.py
!/scripts/tests/
!/scripts/tests/**
scripts/tests/__pycache__/

# arlink reference clone — read-only Claude context, never committed.
# Anchored: it is cloned to the repo root, and it is a dot-directory, so the
# unanchored form also reached inside work-app/ past the `!work-app/**/.*`
# escape.
/.arlink-reference/

# Agent working artifacts (investigation transcripts, journals)
.claude/audit-run/
!/scripts/backfill_devapi_key_scopes.py

# M5-2a: the starlight-openapi API reference renders from a spec VENDORED into
# the docs tree by frontend/docs/scripts/sync-openapi-spec.mjs (run in the docs
# `prebuild`). It is generated from developer-contract/openapi.json (~1.7MB), so
# it is ignored for the same reason developer-contract/ is — committing it would
# add a ~1.7MB diff on every route change. The small, hand-reviewable version
# signal IS committed: frontend/docs/src/data/contract-version.json. To render
# in an environment that cannot build the bundle, either commit this file
# deliberately (the sync `--check` mode supports that) or add the bundle build
# to that pipeline.
/frontend/docs/src/openapi/
!/scripts/collapse_email_conversation_tasks.py

# Read-only cross-org LinkedIn budget collision detector (Phase 4 groundwork).
!/scripts/detect_cross_org_linkedin_collisions.py
