---
title: Contributions — Reference
---

# Contributions — Reference

Contributions track **outbound upstream work** — things identified for a
repository the fleet does not own or control. Each contribution is a
structured artifact filed locally under `contrib/` and registered in State Hub
so it is not lost.

Contributions are **not** a work-record kind in the fleet registry
(`work-record-types_v0.1.md`). They are a separate hub entity and dashboard
surface used for third-party coordination. Work-record kinds cover internal
coordination (workplan, task, intake, decision, engagement, register-entry).
See [Work Records](/docs/work-records).

---

## Contribution types

| Type | Full name | Use when |
|------|-----------|----------|
| `br` | Bug Report | Defect in an upstream tool or library |
| `fr` | Feature Request | Functionality upstream does not yet provide |
| `ep` | Extension Point | Future enhancement opportunity in upstream code |
| `upr` | Upstream PR | Patch written (or being written) for an upstream repo |

---

## Lifecycle (workstations)

Contribution status is evaluated by the task-flow engine
(`flows/contribution.yaml`). The stored field is `status`; flow tooling may
call the same value a **workstation**.

```text
draft → submitted → acknowledged → accepted → merged
                 ↘               ↘
               rejected        withdrawn
```

| Status | Meaning |
|--------|---------|
| **draft** | Artifact written locally; not yet sent upstream |
| **submitted** | Filed as a GitHub issue, PR, or email — awaiting upstream response |
| **acknowledged** | Upstream has seen it and responded (e.g. triaged, commented) |
| **accepted** | Upstream agreed to take action |
| **merged** | PR accepted and merged; issue resolved |
| **rejected** | Upstream declined; record kept for future reference |
| **withdrawn** | We decided not to pursue it |

Reachability is assertion-based. For example, `rejected` is only enterable from
`submitted` or `acknowledged`; `merged` only from `accepted`. If a target is
not reachable, the API returns structured blocking assertions rather than a
generic “transition not allowed” message.

Timestamps: `submitted_at` is stamped when status becomes `submitted`;
`resolved_at` is stamped when status becomes `merged`, `rejected`, or
`withdrawn` (and related terminal paths as implemented on the status patch).

---

## Relation to the Todo classification

Contributions map to the **Third-party** class in the inter-repo communication
taxonomy:

| Todo class | Mechanism |
|------------|-----------|
| Internal | Workplan file + task in this repo |
| Ecosystem | State hub task with `[repo:<slug>]` prefix |
| **Third-party** | **Contribution artifact in `contrib/` + hub registration** |

Open third-party items are contributions in `draft`, `submitted`, or
`acknowledged`. They appear on the [Todo](/todo) page until the upstream loop
closes (`merged`, `rejected`, or `withdrawn`).

Intakes are **not** third-party contributions: an intake is internal capture of
a spark; a contribution is outbound work aimed at someone else’s repo.

---

## File layout

Each artifact lives in the **current** repo under `contrib/`:

```text
contrib/
  bug-reports/        br-YYYY-MM-DD--<org>--<repo>--<slug>.md
  feature-requests/   fr-YYYY-MM-DD--<org>--<repo>--<slug>.md
  extension-points/   EP-<DOMAIN>-NNN--<org>--<repo>--<slug>.md
  upstream-prs/       upr-YYYY-MM-DD--<org>--<repo>--<slug>.md
```

Templates: `~/the-custodian/canon/standards/contrib-templates/`.
Convention: `~/the-custodian/canon/standards/contribution-convention_v0.1.md`.

---

## Adding a contribution

**1. Write the artifact file** using the appropriate template.

**2. Register it in the state hub** (MCP):

```text
register_contribution(
  type                 = "fr",
  title                = "Add sidebar TOC injection API",
  target_org           = "observablehq",
  target_repo          = "framework",
  body_path            = "contrib/feature-requests/fr-2026-02-26--observablehq--framework--toc.md",
  related_workplan_id  = "<uuid>"   # preferred; related_workstream_id still accepted as alias
)
```

REST: `POST /contributions/` with the same fields.

**3. Close the loop** when filed upstream — advance via flow tooling or status
patch:

```text
advance_workstation(entity_type="contribution", entity_id="<uuid>", target_workstation="submitted")
```

```bash
curl -X PATCH "http://127.0.0.1:8000/contributions/<uuid>/status" \
  -H "Content-Type: application/json" \
  -d '{"status": "submitted"}'
```

**4. Keep updating** as upstream responds — `acknowledged`, `accepted`,
`merged` (or `rejected` / `withdrawn`).

Optional links: `related_topic_id`, `related_workplan_id`, `repo_id` (managed
repo that owns the local artifact).

---

## Kanban board

The Contributions page groups artifacts by status column. Only columns with at
least one entry are shown. The **follow-up banner** appears when any
contribution has been in `submitted` or `acknowledged` for an extended period
without further movement — a prompt to check in with upstream.

Data source: `GET /contributions/`.

---

*Contributions are retained after rejection or withdrawal — institutional
memory for why certain approaches were tried and dropped.*
