prodc
Product management as code. You write user needs in YAML. Each need lists the evidence that a real user asked for it, and the test that shows it is delivered. The files live in the repo, next to the code.
prodc reads the YAML files and your test suite, and shows what is missing. It does not call a model, run a UI, or replace your issue tracker.
It follows two rules:
- A need with no evidence is an opinion. Record who asked (an interview quote, a ticket, an email). If you don't, prodc marks the need as an opinion.
- You never mark a need as done by hand. You attach a proof, which points to a test, and
prodc statuscomputes the state: DELIVERED, PENDING, HOLE, or BROKEN.
Compared to other tools
- Jira, Linear and other trackers store work items with a status that someone sets by hand.
prodc stores needs and computes their status from tests. It has no assignees, sprints, or
notifications. You can use both: a source can point to a GitLab ticket (
kind = "gitlab", read-only), a proof can be any script (kind = "command"), andprodc syncruns a hook when a need changes state. - A PRD in Notion or a wiki is not checked after it is written. prodc files are validated on every load, linted in CI, and reviewed in merge requests.
- You could keep the same YAML by hand. prodc adds the schema, proof checks against real test suites, the source kinds, the lint, and write commands that keep the files consistent.
prodc does not run your tests, call an LLM, or contact a tracker by itself. It does not model the full discovery process (opportunity-solution trees, testing several solutions in parallel). It records needs, their evidence, and the decisions made about them.
Install
pip install prodc # or: uv add prodc
Python 3.12+. The only runtime dependency is PyYAML.
Quickstart
You need three files: the config, the needs, and a test.
prodc.toml
[prodc]
files = ["needs/*.yaml"]
[proofs.web]
kind = "gherkin"
paths = ["features/*.feature"]
delivered = ["@implemented"]
pending = ["@pending"]
needs/jordan.yaml
who: jordan
needs:
- id: N-1
text: "see which orders are past due at a glance"
must: true
sources:
- kind: primary
who: Jordan
date: 2026-09-20
quote: "I lose the past-due ones in the list"
proofs:
- "web:orders.feature#Past due orders are highlighted"
- id: N-2
text: "export the day's delivery run sheet"
sources:
- kind: secondary
locator: issues.md#N-2
date: 2026-09-21
- id: N-3
text: "implement a settings page"
features/orders.feature
Feature: Orders board
@implemented
Scenario: Past due orders are highlighted
Given an order whose due date has passed
When I open the orders board
Then the order is highlighted as past due
Run prodc status (output trimmed):
$ prodc status
gaps: 2 HOLE · 1 opinion coverage 1/3 (33%)
jordan 1 DELIVERED 2 HOLE
provenance: 1 primary · 1 secondary · 0 assumption · 1 opinion
N-2 HOLE export the day's delivery run sheet secondary
N-3 HOLE implement a settings page opinion
⚠ text may be a solution in disguise (starts with 'implement')
!! N-1 DELIVERED* 1/1 see which orders are past due at a glance primary:Jordan
⚠ DELIVERED on an unattested proof link (warrant not reviewed)
N-1 is DELIVERED because a tagged scenario proves it. The * means the state comes from the tag,
because no test results were loaded. N-2 has evidence but no proof, so it is a HOLE. N-3 has
neither, so it is an opinion.
You fix these from the command line. Each write command changes one YAML file, validates the whole model again, and prints the diff.
# trace the opinion to evidence
prodc capture N-3 --kind primary --who Jordan --date 2026-10-01 \
--quote "I keep changing the printer in three places"
# add the scenario to your suite, tagged @pending until it is green:
# @pending
# Scenario: Export the run sheet
# then point the need at it:
prodc set N-2 proofs+="web:orders.feature#Export the run sheet"
prodc status # gaps: 1 PENDING · 1 HOLE (N-2 is PENDING: the scenario exists)
# (skip writing the scenario and the proof points at nothing: BROKEN, lint exits 1)
prodc lint # CI gate: exit 1 on a BROKEN proof or a must-have with no evidence
If you rename a scenario and do not update the need, the proof becomes BROKEN and prodc lint
exits 1.
Features
- Source kinds:
primary(the user's own words),secondary(a report, a ticket, an internal doc), orassumption(a guess). A need with no primary or secondary source is an opinion.lintfails on a must-have opinion;status --strictfails on any opinion. - Proof adapters: Gherkin scenarios and tags, pytest node ids, file existence, human sign-off,
prototypes, citations, eval metric gates, external result files, and a generic
command. Give it cucumber-json or JUnit XML to use real test results instead of tags. - Five states: DELIVERED, PENDING, HOLE, BROKEN, UNRESOLVED. A HOLE does not fail the gate; BROKEN always does. A proof in a sibling repo that is not checked out is UNRESOLVED, not BROKEN.
- Flows: a need with
childrenrolls up its children, withseamproofs for the steps between them. One BROKEN child breaks the flow. The flow is DELIVERED only when every child and seam is. tests/test_models.pybuilds a musil model of the lifecycle and checks every reachable state against the real resolver.- Write commands:
set,capture,accept,attest,withdraw,add. They change only the edited need's block and keep the comments in the rest of the file. All take--dry-runand--expect-sha. - Read commands:
status,show,brief,plan,report --format html(one self-contained HTML file),portfolio, anddiffagainst a snapshot. They take--json. Exit codes: 0 ok, 1 gate failed, 2 config or load error. prodc agent >> AGENTS.mdadds instructions for a coding agent to act as the project's product manager. An agent may recordassumptionorsecondarysources;primaryis only for a real user's own words.prodc guideis a short guide for people.
prodc also has goals, releases, roles, principles, and decisions
(model docs), and the commands dupes,
recurrence, and suggest. See the docs for all of it.
Links
- Repository: https://gitlab.com/cardona-oss/prodc
- PyPI: https://pypi.org/project/prodc/
- Changelog: CHANGELOG.md
- Documentation: https://cardona-oss.gitlab.io/prodc/ (Quickstart, Commands, Model, Config, Lifecycle)
Contributing
Toolchain, CI, and the release process live in CONTRIBUTING.md; build and test
instructions for coding agents are in AGENTS.md. In short: make setup
then make check (lint + typecheck + test); moon run :ci is what CI runs.
License
MIT © Jorge Cardona. See LICENSE.
Metadata
Release files for prodc 0.4.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| prodc-0.4.13.tar.gz | 178.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prodc-0.4.13-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 305.8 kB
Release files / prodc-0.4.13.tar.gz
| Download URL | prodc-0.4.13.tar.gz |
|---|---|
| Size | 178.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0b57dc6601635c4b90880623cbb888f9b35b7571e2d926cd9ad4d4d1f303b20
|
|
BLAKE2b-256 checksum How to use checksums |
bb4495a4a4a7ff68e7796679e16384b4e57caa446242b48023d3282e546ee32a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / prodc-0.4.13-py3-none-any.whl
| Download URL | prodc-0.4.13-py3-none-any.whl |
|---|---|
| Size | 127.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eb16308162c1242884605cf7a65233ce5206586e8a77394319540184643ea3b1
|
|
BLAKE2b-256 checksum How to use checksums |
811ad8ab72a18de3daf28b667724b9b9f10b5743f66171ce81d2da1c721a3d5e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for prodc 0.4.13
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.