TODO:

July 12, 2026 · View on GitHub

This is the project configuration for TODO: <project-name>. Every skill under ../../.claude/skills/ reads the project name from <project-config>/project.md and then loads this manifest to resolve project-specific identity, repositories, mailing lists, and references to the other files in this directory.

Grep for TODO to see every field you still need to fill in:

grep -n TODO projects/<name>/project.md

Identity

KeyValue
organizationTODO: the organization whose defaults this project inherits — e.g. ASF (organizations/ASF/). Default independent (organizations/independent/). See organizations/README.md.
project_nameTODO: e.g. Apache Foo
vendorTODO: e.g. Apache Software Foundation
short_nameTODO: e.g. Foo
product_family_urlTODO: e.g. https://foo.apache.org/

The vendor / project_name pair is what lands in the vendor and product fields of the CVE 5.x record the CVE-JSON generator produces.

Repositories

KeyValuePurpose
tracker_repoTODO: e.g. foo-s/foo-sPrivate security tracker (this repo)
tracker_repo_urlTODO
tracker_default_branchTODO: e.g. mainDefault PR target for the tracker repo
tracker_project_board_urlTODO: URL of the GitHub Project V2 board, if anySecurity board
upstream_repoTODO: e.g. apache/fooPublic codebase where fixes land
upstream_repo_urlTODO
upstream_default_branchTODO: e.g. master (older default) or mainUpstream's default branch — what <default-branch> resolves to. Distinct from tracker_default_branch (the security tracker repo's PR target)
upstream_agents_md_urlTODO: https://github.com/<upstream>/blob/main/AGENTS.mdConventions this repo mirrors
upstream_contributing_docs_urlTODO
upstream_genai_disclosure_anchorTODO: URL + anchor for the project's Gen-AI disclosure guideline
upstream_security_policy_urlTODO: https://github.com/<upstream>/security/policy

Mailing lists

KeyValueNotes
security_listTODO: e.g. security@foo.apache.orgInbound reports; not publicly archived
private_listTODO: e.g. private@foo.apache.orgPMC escalation; not publicly archived
users_listTODO: e.g. users@foo.apache.orgPublic advisories end up here; publicly archived
dev_listTODO: e.g. dev@foo.apache.orgRelease [RESULT][VOTE] threads; publicly archived
announce_listTODO: e.g. announce@apache.orgCross-project announcement list; publicly archived
commits_listTODO: e.g. commits@foo.apache.orgPublicly archived

Only URLs on publicly archived lists may appear in CVE references[] as vendor-advisory; see ../../AGENTS.md and security-model.md.

The foundation-wide security forwarding address (e.g. security@apache.org for ASF projects) is org-level — inherited from your organization's security_inbox.foundation_security_address. Do not declare it here.

Tools enabled

CapabilityToolAdapter directoryConfig knobs declared here
Issue tracking + project boardgithub../../tools/github/tracker_repo, upstream_repo, github_project_board_*, issue_template_fields
Source control (VCS)github (Git) — replaceable with a non-Git VCS../../tools/github/source-control.mdupstream_repo, default_branch; for a non-Git VCS declare the sibling tool + its working-copy URL
Inbound email / drafts<one or more mail-source backends>../../tools/mail-source/contract.md (abstract) + per-backend adapter dirs (tools/gmail/, tools/ponymail/, tools/mail-source/imap/, tools/mail-source/mbox/, ...)See Mail sources below — declare each backend's role (primary / preferred-for-<op> / fallback / optional) and mandatory flag
CVE allocation + record mgmtorg-level — inherited from organizations/<org>/organization.md → cve_authority.tool; for ASF: vulnogram (tools/cve-tool-vulnogram/), for independent: mitre-formoverride in CVE authority only if this project differs from its org
Project metadata (rosters / people / releases)org-level — inherited from organizations/<org>/organization.md → project_metadata.kind; for ASF: apache-projects (tools/apache-projects/), for independent: noneoverride in Project metadata only if this project differs from its org
Release commsTODO: the backend that carries release announcements — for ASF: dev_list / announce_list / users_list; for GitHub Releases leave blankwhichever release-comms keys the org default or per-project override declares

To replace a tool (e.g. swap GitHub issues for JIRA), declare an alternate tool in the table above, add a tools/<name>/ adapter directory, and make sure the values the generic skills need are still reachable from this manifest.

CVE tooling

The CNA tool, allocation URL, record URL template, and allocation gate are org-level — inherited from your organization's cve_authority and governance blocks (see organizations/ASF/organization.md for ASF defaults, organizations/independent/organization.md for the GitHub-native baseline). Override a key in the Security workflow configuration → CVE authority block only if this project's CNA setup genuinely differs from its organization.

For ASF adopters, fill in the per-project CNA queue fields below — each ASF project has its own queue slug and org UUID, so these are not org-level:

KeyValue
asf_org_idTODO: project's CNA org UUID — e.g. f0158376-9dc2-43b6-827c-5f631a4d8d09
cna_private_ownerTODO: e.g. foo (CNA_private.owner — the project slug inside the ASF CNA queue)
cna_private_projecturlTODO: e.g. https://foo.apache.org/
cna_private_userslistTODO: e.g. users@foo.apache.org

GitHub project board

If the project uses a Projects V2 board for its security-issue view, declare the node IDs below. Fetch with the introspection query in ../../tools/github/project-board.md. If the project does not run a board, leave the table blank — skills treat missing board config as "no board reconciliation".

KeyValue
project_board_urlTODO
project_board_numberTODO
project_board_node_idTODO
status_field_node_idTODO

Status column → option-ID mapping (re-fetch if any write returns not found):

ColumnOption ID
Needs triageTODO
AssessedTODO
CVE allocatedTODO
PR createdTODO
PR mergedTODO
Fix releasedTODO
AnnouncedTODO

Mail sources

The skills treat every supported mail backend the same way — through the abstract operations defined in ../../tools/mail-source/contract.md. The adopter declares which backends are configured, what role each plays, and whether any are mandatory. The skill's resolution rule (see the contract) then picks the right backend per operation at run time.

Backend declaration

One row per configured backend. Exactly one row carries role: primary. Multiple rows may carry preferred for <op> to override the primary for specific operations. fallback rows are tried in order when no preferred / primary backend supports the op. mandatory: yes means the skill refuses to run when that backend is unavailable; no means the skill continues with the remaining backends (and skips ops that no available backend supports).

BackendRoleMandatoryNotes
TODO: gmailTODO: e.g. primaryTODO: yes / noTODO: e.g. "Triager Gmail account subscribed to <security-list> and <private-list>"
TODO: ponymailTODO: e.g. fallback or preferred for thread_urlTODO: yes / noTODO: e.g. "Read-only archive backstop; install per tools/ponymail/tool.md"
TODO: (add more rows as needed — imap, mbox, project-specific adapter)

Mail backend selection is org-level. The mail_provider block in your organization manifest sets the primary and fallback backends (for ASF: primary: gmail-mcp, fallback: ponymail; for independent: primary: none, fallback: none). Only declare backends here that override or extend what the organization manifest provides. For ASF projects where PonyMail is the inherited fallback, declare it here only to change its mandatory flag or role for this specific project; the backend itself is already wired by the organization. Install PonyMail per ../../tools/ponymail/tool.md.

Reference adapter docs: tools/gmail/tool.md (full read+write), tools/ponymail/tool.md (read-only ASF archive), tools/mail-source/imap/README.md (stub), tools/mail-source/mbox/README.md (read-only offline archive — stub).

Per-backend config

Per-backend values the generic recipes substitute in. Only fill in the rows for backends declared above; leave the rest blank or remove the row.

KeyBackendValue
security_list_domaingmailTODO: e.g. security.foo.apache.org — Gmail list: operator uses the domain form
ponymail_private_search_url_templateponymailTODO
ponymail_public_search_url_templateponymailTODO
ponymail_api_url_templateponymailTODO
ponymail_thread_url_templateponymailhttps://lists.apache.org/thread/<hash>?<list>
imap_hostimapTODO: e.g. imap.example.org
imap_accountimapTODO: e.g. security-triage@example.org
imap_security_list_folderimapTODO: e.g. INBOX.security-list
imap_drafts_folderimapTODO: e.g. Drafts (or leave blank to declare create_draft unsupported on this adapter)
mbox_archive_pathmboxTODO: e.g. /srv/audit/security-list-2024.mbox

Issue-template fields

The skills' body-field roles map to the following concrete ### headings in the project's issue template (the concrete YAML file lives in the adopter's <upstream> repo; the generic role → field contract is in The generic role → GitHub-field contract lives in ../../tools/github/issue-template.md; the concrete names below are what skills read and write for this project.

Role (generic)Field nameTemplate typeRequired?
issue-descriptionTODOtextareaTODO
public-summaryTODOtextareaTODO
affected-versionsTODOinputTODO
security-threadTODOinputTODO
public-advisory-urlTODOinputTODO
reporter-creditTODOinputTODO
pr-with-fixTODOinputTODO
cweTODOinputTODO
severityTODOdropdownTODO
cve-tool-linkTODOinputTODO

Security workflow configuration

Skills resolve every workflow knob from the three-layer chain project.md → organizations/<org>/organization.md → framework default (see AGENTS.md § Configuration resolution order). The organization you named under Identity supplies the org-wide defaults — the CNA tool, the governance gate, the mail / forwarder / archive backends, the project-metadata source, and the release-manager lookup cascade. For an ASF project these resolve to the Vulnogram / PonyMail / apache-projects-mcp / ASF-security values in organizations/ASF/organization.md; organization: independent inherits the GitHub-native baseline in organizations/independent/organization.md.

Declare below only what is specific to this project. Each block that is purely org-level says so and shows nothing — copy the matching key from the organization manifest down into that block only to override it (the project value wins). The blocks that every adopter fills in keep their per-project keys.

CVE authority

Org-level — inherited from your organization's cve_authority block (CNA tool, allocate / record / source-tab URLs, state mapping, propagation, allocation-email flag, reviewer channel). Override a single key here only if this project's CNA setup differs from its organization.

Governance

Org-level except the escalation contact: the allocation gate, gate label, release-vote gating, private governance list, and roster URL are inherited. Declare this project's escalation contact:

governance:
  # GitHub handle (or external contact) the skills cc / @-mention when
  # escalating beyond the security team.
  # Consumed by: security-issue-sync, pr-management-triage.
  escalation_contact: "@<escalation-contact>"

Security inbox

Org-level except the concrete address: the inbox kind, the foundation security address, the has_forwarder_relay flag, and the list filter are inherited. Declare this project's inbound address:

security_inbox:
  # The concrete inbound address / channel ID / form URL for this project.
  # Consumed by: security-issue-import, security-issue-sync, canned-responses.
  address: <security-list>

Forwarders

Org-level — inherited from your organization's forwarders block (which relay adapters are enabled and their per-adapter detect / credit rules). Override here only to enable an extra relay this project uses.

Mail provider

Org-level — inherited from your organization's mail_provider block (primary + fallback mail backends). Override here only if this project reads mail from a different backend than its organization.

Archive system

Org-level — inherited from your organization's archive_system block (public-archive backend + URL templates). Override here only if this project's advisories surface on a different archive than its organization.

Project metadata

Org-level — inherited from your organization's project_metadata block (roster / people / releases backend + whether it is mandatory). Override here only if this project uses a different metadata source.

Tracker

The tracker platform, board, visibility, and skill_url_template are org-level defaults — override them here only if this project differs (e.g. a project that runs its security tracker publicly sets visibility: public). Declare this project's per-tracker vocabulary:

tracker:
  # Whether the reporter can see the tracker issue once opened.
  reporter_has_access: false

  # Whether the tracker drives a board / kanban view.
  project_board_enabled: true

  # Body-field heading names — role -> the concrete `###` heading in this
  # project's issue template. Skills refer to these by role.
  # Consumed by: every skill that reads/writes the issue body.
  body_fields:
    cve_link: "CVE tool link"
    mailing_thread: "Mailing list thread URL"
    affected_versions: "Affected versions"

  # Tracker labels — role -> the concrete label name in this project.
  # Consumed by: security-issue-triage, security-issue-sync, pr-management-triage.
  labels:
    security_marker: "security"
    needs_triage: "needs triage"
    pr_open: "pr created"
    pr_merged: "pr merged"
    cve_allocated: "cve allocated"
    not_cve_worthy: "not cve worthy"
    # Label on the single open "rejected without tracker" ledger issue
    # (see below). NOT the security_marker label.
    rejections_ledger: "rejections-ledger"

Rejected-without-tracker ledger

The security-issue-import skill sometimes rejects a report with a canned reply without creating a tracker (the disposition lives only on the mail thread). To keep those rejections countable, the team records each one as a comment on a single dedicated ledger issue in tracker_repo: one open issue, labelled with the tracker.labels.rejections_ledger value (default rejections-ledger) and not carrying the security-marker label.

Adopters who want the rejected without tracker dashboard stat must:

  1. Create the ledger issue once in tracker_repo and label it rejections-ledger (keep it open; the skills resolve it via gh issue list --repo <tracker> --state open --label rejections-ledger).
  2. Set the dashboard knob. Point security-tracker-stats.md → rejections_ledger_label (or the rejections_ledger_label: key in the renderer's YAML overlay) at the same label. Set it to null to disable the stat — then no ledger issue is needed.

Each rejection comment carries a machine-parseable block (<!-- rejection v1 --> with date: / reporter: / canned: / thread: / summary: lines); a one-time historical backfill is a single <!-- rejection-backfill v1 count: N --> comment. The security-tracker-stats-dashboard renderer parses these and excludes the ledger issue from all tracker classification. Closes handled by security-issue-invalidate are not ledger entries.

Scope detection

Per-project — whether this project distinguishes scope sub-products, and the label → sub-product map:

scope_detection:
  # When false, every issue maps to the single product in the `product` block.
  # Consumed by: security-issue-triage, generate-cve-json, security-issue-sync.
  enabled: true

  # Scope label -> sub-product: tracker label -> CVE product / packageName
  # / upstream path-prefix the skill uses to confirm a PR touches that scope.
  labels:
    <scope-label>:
      product: "<Product Name>"
      packageName: "<package-name>"
      path_prefix: "<path-prefix-regex>"
    <secondary-scope-label>:
      product: "<Secondary Product Name>"
      packageName: "<secondary-package-name>"
      path_prefix: "<secondary-path-prefix-regex>"

Release process

The release-manager lookup cascade and artifact registries are org-level and inherited. Declare this project's stale milestones and changelog fragment tool:

release_process:
  # Milestones the skills treat as "stale" (overdue for re-targeting) —
  # exact milestone-name matches.
  # Consumed by: security-issue-sync, pr-management-triage.
  stale_milestones:
    - "<stale-milestone-1>"
    - "<stale-milestone-2>"

  # Whether the upstream repo uses a changelog-fragment tool, and which one.
  # Consumed by: security-issue-fix, issue-fix-workflow.
  newsfragments:
    enabled: true
    tool: <fragment-tool>

Roster

The roster source is org-level and inherited. Declare this project's bare-name → handle map and release managers:

roster:
  # Mailing-list threads reference contributors by first name; this binds
  # those to GitHub handles for @-mentions.
  # Consumed by: security-issue-sync, pr-management-mentor.
  bare_name_handles:
    # Example (replace with your project's contributors):
    "<FirstName>": "@<handle>"

  # Release-manager handles, current first. Keep in sync with release-trains.md.
  # Consumed by: security-issue-sync, security-issue-fix.
  release_managers:
    # Example (replace with your project's release managers):
    - "@<handle>"

Product

Per-project — the product identity used in CVE records, advisories, and title normalization:

product:
  # Human-readable product name — lands in the CVE record's `product` field.
  # Consumed by: generate-cve-json, canned-responses templating.
  name: <ProjectShortName>

  # Package-name shape for the primary artifact (PyPI / npm / Maven).
  # Consumed by: generate-cve-json, canned-responses templating.
  package_name: <package-name>

  # Regex matched against changed paths in an upstream PR to confirm
  # "this PR really touches the product" — a backstop in the fix flow.
  # Consumed by: security-issue-fix, pr-management-triage.
  code_pointer_path_prefix: "<code-path-prefix-regex>"

  # Prefixes the title-normalization skill strips from an inbound subject
  # when building a CVE title (matched at the start, case-insensitively).
  # Consumed by: title-normalization, generate-cve-json, canned-responses.
  subject_prefix_strip:
    - "[SECURITY]"
    - "[Security Report]"
    - "Re:"
    - "Fwd:"
    - "<vendor>:"
    - "<vendor> <product>:"

  # Prefix the affected-versions extractor strips to leave the bare version.
  # Consumed by: security-issue-sync, generate-cve-json.
  affected_version_extract_prefix: "<ProjectShortName>"

Pointers to sibling files