-
Notifications
You must be signed in to change notification settings - Fork 4.4k
14.5 Contribution Culture
Source: #5615 Ā· Part of the Maturity Framework. This page mirrors the RFC body; discussion lives on the issue.
A note to the team before you read this.
This is the fifth document in ZeroClaw's maturity framework. The other four address architecture, documentation, governance, and engineering infrastructure ā the structural layers that make a project work. This one addresses something those four take for granted but never explicitly teach: how to work together.
The tools and processes in the other RFCs only function as well as the team using them. A perfect CI pipeline does not help a team that cannot give honest feedback. A clean architecture does not survive a team that cannot disagree productively. A governance model does not build ownership in people who have never been taught what ownership means.
This document is about building that team ā not just technically capable individuals, but people who know how to give and receive feedback, how to ask for help, how to use powerful tools responsibly, and how to grow together over time. These are learnable skills. Nobody arrives with them fully formed. This document names them clearly enough that you can start practicing them deliberately, here, in the context of real work that matters.
Nothing in this document is criticism of who you are or where you started. It is a map for where we are trying to go together.
This RFC is the fifth in a set of five documents that together form ZeroClaw's maturity framework. They are designed to be read as a whole, though each stands on its own.
| RFC | Scope | Issue |
|---|---|---|
| Intentional Architecture ā Microkernel Transition | What we are building and how it is structured | #5574 |
| Documentation Standards and Knowledge Architecture | How we document what we build | #5576 |
| Team Organization and Project Governance | How we coordinate and make decisions | #5577 |
| Engineering Infrastructure ā CI/CD Pipeline | How we build, test, and ship reliably | #5579 |
| Contribution Culture ā Human Collaboration and AI Partnership | How we work together and grow | this RFC |
The first four RFCs answer structural questions. This one answers a human question: given the structure, how do the people inside it behave toward each other and toward their tools? That question does not have a compiler, a linter, or a CI gate. It has only the habits we build, the examples we set, and the intentionality we bring to it.
- Why this document exists
- The work before the work
- Working with people
- Working with AI
- The feedback taxonomy
- A note to reviewers and mentors
- Discussion Questions for the Team
Most contributing guides tell you how to open a PR. They tell you what labels to use, how to run the test suite, and what goes in the commit message. Those things matter, and we have documents that cover them.
This document covers something different: the skills that determine whether a group of talented people becomes a functional team or a collection of individuals who happen to share a repository.
These are learnable skills. They are not personality traits you either have or do not have. They are not things that come automatically with technical ability. They are practiced ā slowly, with feedback, over time ā the same way any other skill is learned. Most software engineering education focuses almost entirely on the technical layer and leaves the human layer to chance. The result is that a lot of technically capable people end up in teams that do not work well together, without any clear understanding of what is missing or how to fix it.
The goal of this document is to name those skills clearly enough that you can start practicing them deliberately, here, in the context of real work that matters.
Before you write a line of code, open a PR, or ask an AI to generate anything, there is a set of questions you should be able to answer. This project uses a decision hierarchy to describe them:
Vision
āāā Architecture
āāā Design
āāā Implementation
āāā Testing
āāā Documentation
āāā Release
The hierarchy is described in full in the architecture RFC (#5574). What matters here is the principle behind it: every decision you make should be traceable back up to the top.
In practice, this means asking yourself before you start building:
- What problem am I solving? Not "what ticket am I closing" ā what actual problem does this solve for someone?
- Does this fit the architecture? If you cannot describe where this belongs in the system structure, you do not yet understand the system well enough to change it.
- What does done look like? Before you write the code, write the acceptance criteria. "It works" is not an acceptance criterion. "A user can install a plugin without a Rust toolchain and it runs correctly" is.
- Who needs to know about this? Changes that touch other people's work, or that make decisions the whole team should make, need visibility before implementation ā not after.
This is not bureaucracy. It is the difference between building something and building the right thing. It also applies directly to how you work with AI tools, which we cover in Section 4.
The honest version of what happens when you skip this step: you build something that works, open a PR, and then learn in the review that it solves the wrong problem, or solves the right problem in a way that conflicts with a decision that was already made somewhere else. That wastes your time, the reviewer's time, and delays the people who depend on the work. The pre-work is not extra ā it is how you protect your own effort.
Feedback is one of the highest-leverage things you can do for another engineer. A well-written review comment can teach something that takes years to learn on your own. A poorly written one can discourage someone from contributing again.
Be specific. Vague feedback creates anxiety without direction.
ā "This is hard to read."
ā "This function is handling three separate concerns ā input validation, business logic, and formatting the response. Consider splitting them so each function does one thing. That makes it easier to test each piece and easier to understand at a glance what each one does."
The second version is longer, but it teaches something. The reader now knows what the problem is, why it matters, and what to do about it.
Explain the principle, not just the verdict. If you ask someone to change something, tell them why. "Change X to Y" produces a fix. "Change X to Y because Z" produces understanding that applies to the next ten situations where the same principle applies.
Separate the work from the person. "This approach has a problem" and "you made a mistake" are not the same statement. The first is about the code. The second is about the person. Keep your feedback pointed at the work.
Name what is good. This is not about being nice ā it is about being useful. When you tell someone what they got right and explain why it is right, you teach them what patterns to repeat. Generic praise ("great work!") teaches nothing. Specific praise ("extracting this into its own crate was the right call because it means we can now test this logic in isolation without standing up the whole agent loop") teaches the principle and reinforces the decision.
Use the feedback taxonomy. The four-bucket model in Section 5 gives every comment a clear weight. Reviewers who mix blocking issues with minor suggestions without distinguishing between them force the author to guess which things actually need to change. Do not make people guess.
This is harder than giving feedback for most people, and it is worth being honest about why.
When you have spent hours on something ā working through a problem, making decisions, writing the code ā and someone tells you it has issues, the natural human response is to feel like the criticism is about you. It is not. It is about the work. Learning to hold those two things as separate is a skill, and it takes practice.
A few things that help:
Read the feedback before you respond to it. Not just the summary line ā the whole comment, including the explanation. Many feedback responses are written in reaction to the verdict before the person has absorbed the reasoning. Read the why before you decide how you feel about the what.
Distinguish between "I disagree" and "I do not understand." These require different responses. If you do not understand the feedback, ask a clarifying question. If you understand it and disagree, say so with evidence. Both are good outcomes. What is not useful is staying silent when you have questions, or saying "ok fine" when you actually disagree.
You do not have to agree with every piece of feedback to learn from it. Sometimes feedback is wrong. Sometimes it reflects a different set of tradeoffs than the ones you were optimising for. You are allowed to push back ā see Disagreeing productively below. But even feedback you ultimately reject is worth understanding fully before you decide to reject it.
Close the loop. When someone takes time to review your work, tell them when you have addressed their feedback. You do not have to thank them effusively ā a simple "addressed in the latest commit" is enough. It tells them their time was worthwhile and keeps the PR moving.
Feedback on your code is not feedback on your worth. This sounds obvious. It is not obvious when you are in the middle of it. Every experienced engineer has code reviewed by people who are more experienced, and that process is uncomfortable every time. The discomfort is the sensation of learning. It does not go away; you just get better at sitting with it.
In school, asking for help can feel like admitting you are behind, or that you do not belong. In a team, asking for help is one of the most professional things you can do.
The cost of being stuck and not asking is almost always higher than the cost of asking. Three hours of spinning on a problem that a five-minute conversation would resolve is three hours of your time and your team's time that is gone. Knowing when to ask is a skill, not a weakness.
A good help request has three parts:
- What you are trying to do. Not just "it's broken" ā what is the goal?
- What you have already tried. This shows you have engaged with the problem and gives the person helping you a starting point that is not zero.
- Where you are stuck specifically. "I don't know what's wrong" is a different problem than "I know what's wrong but I don't know how to fix it" and "I fixed it but I don't know why my fix works."
A help request that has these three components gets answered faster and teaches you more, because the person helping you can calibrate to exactly where you are.
Ask publicly when you can. A question asked in a shared channel or on a PR benefits everyone who has the same question later. A question asked privately benefits only you. There are times when private is right ā sensitive feedback, personal circumstances ā but technical questions about the codebase are almost always better asked in the open.
Not knowing something is not shameful. Nobody knows everything. The engineers who appear to know everything have asked a lot of questions over a long time, and the answers accumulated. The only way to get there is to start asking.
Architecture disagreements are healthy. They mean people care about how the system is built and are paying attention to the decisions being made. A team where nobody disagrees is not a team where everyone agrees ā it is a team where people have stopped engaging.
The difference between a productive disagreement and an unproductive one is usually in the framing.
Lead with the concern, not the verdict.
ā "This approach is wrong."
ā "I have a concern about this approach ā specifically, if we wire the gateway directly into the runtime here, we break the dependency rule in RFC §4.2. Can we talk through whether there is a way to achieve the same result without that coupling?"
The second version opens a conversation. The first closes one.
Bring evidence. An architecture disagreement backed by a measured fact, a specific RFC section, or a concrete failure scenario is a contribution. An architecture disagreement backed by "I just feel like" is an opinion. Both are worth expressing, but only one moves the conversation forward quickly.
Be genuinely open to being wrong. If you go into a disagreement having already decided you are right, you are not having a conversation ā you are lobbying. People can tell the difference, and it makes them less likely to engage seriously with your concerns. The goal is the best outcome for the project, not being right.
When the team decides, move with the team. You can note your dissent on the record ā in the issue, in the RFC comments, in the PR thread ā and then you build what was decided. This is not capitulation. It is how teams function. A team that keeps relitigating settled decisions does not ship.
Some decisions are reversible and some are not. Know which kind you are arguing about. A naming decision is reversible. A wire protocol decision that will be in production binaries for two years is not. Weight your energy accordingly.
Ownership is one of those words that gets used a lot without a clear definition. Here is what it means in practice on this project:
Ownership means you see the problem before you are asked to. It means reading a PR that touches your area and noticing a side effect the author did not notice. It means seeing a follow-up issue sitting without an assignee and picking it up. It means not waiting to be told.
Ownership means your word means something. If you file a follow-up issue with your name on it, that issue is your commitment. Not "someone should do this" ā you will do this. If circumstances change and you cannot, you say so early and you find a handoff. A tracker full of filed-and-forgotten issues with names attached is a broken trust register.
Ownership is not "I did my part." It is "I care whether the whole thing works." You can own a crate without being indifferent to whether the system that crate lives in is healthy. You can own a feature without being indifferent to whether users can actually use it. Narrow ownership ā "I did my bit, the rest is someone else's problem" ā produces systems that technically have owners for every piece and functionally have no one responsible for anything.
Ownership includes the follow-through. Shipping code is not the end of ownership. It is the beginning of the responsibility to make sure it works, to fix what breaks, and to teach the next person who works in that area what you learned.
At some point in this project you will be more experienced than someone else in a thread. Maybe you have been here longer. Maybe you happen to know the part of the codebase they are working in. Maybe you have seen this particular failure mode before.
What you do with that position matters.
Do not just fix it for them. Giving someone a working solution without explaining what was wrong or why your solution works produces a merged PR and zero learning. The next time they hit a similar problem, they will be in the same place. Take the extra five minutes to explain what you saw and why the fix works.
Review with intent to teach. A bad PR is not just a problem to close ā it is a teaching opportunity. A dismissive review ("this doesn't follow the architecture") is less useful than a review that names what was missed, explains the principle it violates, and points to where the contributor can learn more. The extra effort is an investment in a contributor who writes better PRs from that point forward.
If someone is blocked and not asking for help, say something. Sometimes people do not ask because they do not want to look like they are struggling. Sometimes they are not sure who to ask. Sometimes they have been struggling long enough that they have stopped noticing how stuck they are. A quiet "looks like this one has been open for a while ā is there anything I can help unblock?" costs almost nothing and can mean everything to someone who is spinning.
Make it safe to not know things. If people in your team feel judged for not knowing something, they will pretend to know things. That produces worse decisions, not better ones. The team that makes it safe to say "I don't know, let me find out" makes better decisions than the team where everyone performs confidence.
This section is about something that most contributing guides do not cover: how to work with AI coding tools in a way that makes you better, not just faster.
Here is the most useful reframe for working with AI effectively:
Working with an AI is the same skill as delegating to a person.
When you delegate work to a colleague or a junior engineer, you provide context. You explain the goal, the constraints, what good looks like, and what the boundaries are. You do not just say "build me a feature." You say: here is what the user is trying to do, here is how it fits into the system, here is how we will know it is done, and here are the things you should not do.
Then ā critically ā you review what comes back. You do not accept a junior engineer's PR without reading it. You check whether it does what was asked, whether it fits the architecture, whether it has test coverage, whether the error handling is correct. You give feedback. You may iterate.
AI tools work exactly the same way. The quality of what you get back is determined almost entirely by the quality of what you put in. A vague prompt produces vague output. A prompt with clear context, specific constraints, and concrete acceptance criteria produces output that is actually useful as a starting point.
The engineers who struggle with AI tools are usually the ones who are still learning to give clear direction to anything ā human or AI. The engineers who thrive with them are the ones who already know what they want before they ask for it.
This mental model also means that the output is your responsibility. You cannot submit a PR and say "the AI wrote it." You reviewed it. You opened the PR. It is your work.
This is the most important technical limitation to understand.
AI code generation works at the implementation layer of the decision hierarchy:
Vision ā AI cannot set this. You must.
Architecture ā AI cannot make these decisions. You must.
Design ā AI will sometimes guess. You must verify.
Implementation ā AI can help here.
Testing ā AI can help, but you define what to test.
Documentation ā AI can draft. You must review for accuracy.
Release ā Human judgment required.
An AI tool will generate a function that does what you described. It will not tell you whether that function belongs in this crate or a different one. It will not flag that the approach contradicts an architectural decision made three months ago. It will not ask whether you have thought through the security implications. It will not notice that you are solving the wrong problem.
ZeroClaw itself is a useful example. The initial codebase was bootstrapped with AI assistance. The result, as the architecture RFC describes it, is "impressively functional but architecturally accidental." The code does what it needs to do today ā but it was not designed, it accumulated. That is not a failure of AI tools. It is a predictable outcome of using implementation-layer tooling without first doing the vision, architecture, and design work that gives implementation its direction.
The solution is not to use AI less. It is to do the top-of-hierarchy work yourself, always, before you ask the AI to build anything.
AI tools amplify your existing capabilities. That is the honest description of what they do.
If you have a clear vision, a defined architecture, quality criteria you can articulate, and the ability to evaluate output critically ā AI is a genuine force multiplier. You move faster. You explore more options. You write more tests. You draft more documentation.
If you do not have those things ā AI generates a lot of code that looks convincing and does not hold together. It generates tests that pass without testing anything meaningful. It generates documentation that describes the code but not the intent. It generates architecture that is locally consistent and globally incoherent.
The amplification is neutral. It amplifies good inputs and bad inputs with equal enthusiasm.
This means the most valuable skill in an AI-assisted workflow is not prompt engineering. It is the ability to evaluate the output. That requires knowing what good looks like before you ask for anything. Which brings you back, every time, to the top of the decision hierarchy.
A useful self-check before using an AI tool to implement something:
- Can I describe the problem in one sentence without mentioning implementation details?
- Can I name the RFC section or design decision that this implementation serves?
- Can I describe what a correct implementation looks like before I see one?
- Can I explain why a generated implementation is or is not correct after I see one?
If the answer to any of these is no, you are not ready to implement yet. You are still in the design phase.
AI-generated code requires the same review discipline as human-written code. In some ways it requires more, because the surface area of issues you are checking for is wider.
When you review AI-generated output ā your own or someone else's ā check for:
Architectural fit. Does this respect the dependency rules? Does it live in the right crate? Does it introduce a coupling that the design explicitly avoids?
Correctness at the boundary. AI models are very good at the common case and frequently wrong at the edge case. Check what happens when inputs are empty, null, malformed, or at the maximum expected size. Check what happens when a dependency is unavailable.
Security implications. AI tools do not have a security mindset by default. They will generate code that accepts user input without validation, that logs sensitive values, that uses deprecated cryptographic primitives, that opens file paths without checking them. You have to bring the security lens explicitly.
Test quality. AI-generated tests frequently test the implementation rather than the behaviour. A test that asserts a function returns a specific internal struct value is not a behaviour test ā it is a snapshot of the implementation that will break whenever the implementation changes. Ask: does this test verify that the system does what the user or caller needs, or does it verify that the code does what it currently does?
Completeness. AI tools optimise for plausible-looking completeness. They will generate code that handles the happy path thoroughly and the error path superficially. Check that errors are propagated, handled, or surfaced in a way that is actually useful to the caller.
The skills being described here ā giving direction clearly, evaluating output critically, understanding where a component fits in a larger system, knowing what good looks like before you build ā are not AI-specific skills. They are the skills that make someone an effective engineer, an effective tech lead, and eventually an effective engineering manager.
The engineers who will be most valuable in a world saturated with AI-generated code are not the ones who can write the most code fastest. They are the ones who can tell whether the code is right. That requires system thinking, architectural judgment, and the ability to evaluate work against a standard you have internalised.
Everything you practice here ā understanding the RFC before you implement, asking "why" before you build, reviewing AI output with the same eye you would bring to a junior engineer's PR ā is practice for that kind of judgment. It compounds. Every PR where you engage seriously with the architecture is a data point that makes the next architectural decision easier.
The contributors on this project have an unusual advantage: you are building these habits on a real system, with real architectural constraints, with people who will review your work and explain why. That combination is rare. It is worth taking seriously.
Every review comment on this project carries one of four weights. Using them consistently means reviewers communicate clearly and authors know exactly what requires action.
Something the author got right, named specifically and explained so the pattern gets repeated.
This is not politeness. Generic praise ("nice work!") teaches nothing. Specific praise with an explanation teaches the principle behind what was done well, which applies to every future decision in the same category.
Commendations require no action. Their purpose is to reinforce.
Example: "Extracting the tool call parser into its own crate was the right call ā this code has zero dependencies on agent state and is now independently testable. The 91 tests you added are exactly the kind of coverage that would be impossible to achieve when this logic lived inside
loop_.rs."
Something that must be resolved before the PR merges. Blocking items fall into two categories:
- Architectural violations: code that crosses a dependency boundary the design explicitly prohibits, or that contradicts a decision recorded in an RFC or ADR.
- Quality regressions: missing test coverage for new behaviour, security issues, broken contract compatibility, or code that introduces a defect.
A blocking comment explains what the issue is, why it matters, and ā where possible ā what a resolution path looks like. A blocking comment is not a judgment of the author. It is the reviewer's responsibility to the codebase and the users who depend on it.
Authors should not interpret a blocking comment as rejection. It is a specific, resolvable problem. Address it and move forward.
Something acceptable to defer, but only with a committed tracked issue and an assignee. A conditional item is the reviewer saying: I trust that this will be addressed, but I need that commitment on record before we merge.
The distinction between blocking and conditional is often about timing and risk. A missing feature that will be delivered in the next PR is conditional. A missing feature that creates a security gap is blocking.
A conditional deferral without an assignee is not a deferral ā it is a wish. Tracked issues with no owner tend to stay open indefinitely. When a reviewer marks something conditional, they are asking for a named commitment, not a theoretical future intention.
A question the PR surfaces that no single reviewer or author should answer unilaterally. Team decisions involve tradeoffs that affect the project's direction, its architecture, or its users ā and they belong to the group.
Using this label is how reviewers avoid holding up individual contributors with questions that are really about shared direction. It surfaces the decision, frames the tradeoffs, and asks the team to weigh in ā without making the author feel like their PR is blocked on something that is not in their control.
Team decisions should be answered in the PR thread, on the record, by the people who need to own the outcome. A decision answered in a side conversation that does not appear in the PR thread does not exist for anyone who reads the history later.
If you are in a position of reviewing someone else's work ā whether as a code owner, a more experienced contributor, or simply someone who has been here longer ā this section is for you.
You are modelling what collaboration looks like. Every review you write teaches the author how to review. Every question you ask in a PR thread teaches newer contributors what questions are worth asking. You cannot opt out of this ā the only choice is whether to do it intentionally or accidentally.
Thoroughness is respect. A thorough review that explains its reasoning is more respectful of the author's effort than a quick approval. The author put time into the work. They deserve to understand why it is or is not ready to merge, and what they can take forward from the interaction.
The goal of every review interaction is to leave the author better equipped than they were before. Not just to produce a merged PR. Not to demonstrate your own knowledge. Not to enforce rules. To leave the author with something they can use ā a principle, a pattern, an understanding of a tradeoff ā that applies beyond the immediate PR.
Name the pattern, not just the instance. When you ask for a change, explain the principle behind it. "Rename this variable to something that describes what it contains" is less useful than "variable names should describe their purpose from the caller's perspective, not the implementation's ā what does the caller of this function actually care that this value represents?" The second version applies to every variable in every function the author will ever write.
Be honest about what is your preference and what is a requirement. "I would write this differently" is not the same as "this must change." If you are expressing a preference, say so. If you are citing a hard requirement ā architecture, security, compatibility ā cite the specific reason. Authors who cannot tell the difference between reviewer preference and architectural necessity will either change everything or change nothing. Neither serves them well.
The team you are helping build is the team you will work in. The investment you make in a careful, educational review today compounds into a contributor who writes better code, opens better PRs, and reviews others more thoughtfully. That makes the project better. It also makes your own work easier, because the people around you are growing.
This is not a soft skill. It is engineering work.
This RFC is a proposal, not a policy. Before it is adopted, the team should discuss and reach agreement on the following. There are no right answers ā only the answers that reflect who we actually want to be.
-
Does the framing in Section 2 match how we want contributors to approach new work? Specifically: is requiring traceable intent before building something a reasonable bar for this team, or does it create friction that slows down contributors who are still learning the architecture?
-
Is the AI section (Section 4) accurate to your experience? The delegation mental model and the amplification principle are presented as settled observations. If they do not match what you have found to be true working with these tools, say so. This section should reflect the team's lived experience, not just one person's framework.
-
What is missing from Section 3? The human collaboration section names six dynamics. There are certainly others. What situations have come up on this project ā in PR threads, in issue discussions, in how work gets handed off ā that this document does not yet address?
-
Should the feedback taxonomy (Section 5) be referenced in the reviewer playbook and PR template? If we adopt these four labels formally, they should appear in the places contributors look when they are writing reviews. Where should they live?
-
Does the document strike the right balance between aspirational and practical? A culture document that describes a team nobody recognises will not be read. A document that only describes current behaviour does not help the team grow. Where does this one land, and what would make it more useful?
-
Who should own and maintain this document? The architecture RFC has architectural maintainers. This document, if adopted, needs someone who will notice when it drifts from the team's actual practice and update it accordingly. Is there someone who wants to take that on?
This document was developed as part of the ZeroClaw maturity framework, a set of five RFCs that together describe the structural, operational, and human foundations the project needs to grow sustainably. The maturity framework treats the team itself as an architecture ā something that can be designed with intention rather than left to accumulate by accident.
Feedback, additions, and counterproposals are welcome. The best culture is the one the team understands and believes in ā not the one any single person described.