Collaboration in the age of AI

One of my main goals with AI has been to get collaboration right. It’s very easy to withdraw and try to do it all on one’s own so I’ve tried hard to avoid that.

Lately, I’ve been collaborating with @veelenga as much as I can with GitHub - crystal-autobot/autobot: Ultra-efficient personal AI assistant powered by Crystal · GitHub. I’ve been trying not to overwhelm him because, I assume, he’s busy with other things. That said, 5 PRs at a time have been the norm, hehe.

I know I don’t get it right all the time. Many times, he graciously fixes whatever I got wrong and merges, and I thank him and get it as well. In order to keep it practical, it’s better just to fix than to provide feedback. The feedback is in the code, which I value.

On the other hand, I’ve been trying to contribute to the Amber Framework · GitHub repos. @crimson-knight and other collaborators have been practical about it. If the PR works, they keep it and issue feedback; if it’s too broken, they just close it and provide feedback. I like it. We move fast that way and we’ve been able to work some PRs into the projects.

Additionally, I’ve just contributed a few changes to Zawertun’s GitHub - ZaWertun/fedora-copr-crystal: https://copr.fedorainfracloud.org/coprs/zawertun/crystal/ · GitHub repo. Mainly, taking into account some of @straight-shoota’s advice and in pro of my Crystal in Fedora project.

I did a few changes to Crystalline: GitHub - renich/crystalline: A Language Server Protocol implementation for Crystal. 🔮 · GitHub and ended up maintaining a fork. This is exactly what I want to avoid doing. This is the “Tetsuo syndrome” I identified and am weary of. Yet, the author seemed not willing to take any PRs so I’ve decided to try and continue the work there on my own repo.

Lastly, my Jules ↔ crystal project, which I have poorly paid attention to, has a ton of PRs by Jules but it’s frozen in time. I have to allocate some time to rebase it and figure out which of those PRs are valid.

My intention with that project isn’t really to propose useless PRs to the crystal repo but to evaluate if Jules’ proposals are useful at all. A project like that could add up its PRs easily and constantly through time. If they prove to be useful, hey, a well-managed Jules instance can drastically help with “talacha” work in any project. It’s worth looking into.

The Path Forward: A Deterministic Collaboration Protocol

I feel this is one of our greatest challenges. Not because of the quality of our A.I. agents, but because of human nature. Wielding all this power is hard. Code generation has become incredibly cheap, but we are running the risk of making maintenance and code-review catastrophically expensive. Exporting the AI’s probabilistic flaws to upstream maintainers; essentially using them as human compilers; is an architectural failure that leads directly to burnout.

To fix this, I am restructuring my approach to AI collaboration around three strict rules. I’d love the community’s thoughts on this workflow:

1. Context Before Code (The Consensus Engine)

Before an agent writes a single line of Crystal, it must ingest the relevant module’s commit history, closed PRs, and rejected architectural proposals. The agent shouldn’t pitch code first; it should synthesize the architectural consensus and propose a plan that routes around known historical landmines.

2. Invariants First (The Adversarial Shift)

I am stopping the practice of throwing full implementations at maintainers to see what sticks. If an agent like Jules detects a performance or security issue, Phase 1 is to submit a mathematically undeniable, isolated test that fails. Force alignment on the problem (the boundary condition) before ever debating the solution. Once the maintainer agrees the test should pass, Phase 2 is submitting the fix.

3. Strict Ecosystem Compliance (Zero-Friction Integration)

I am treating repository conventions as rigid APIs. My local orchestration must format agent output to be 100% compliant with the project’s idioms, testing macros, and syntax before a PR is opened. The goal is cognitive load minimization. The reviewer should only have to evaluate the logic of the fix, without parsing alien formatting or debating stylistic choices. Furthermore, submissions must align with the maintainer’s operational cadence; no more dropping 5 PRs at once and creating asynchronous bottlenecks.

In short: AI should not be used to flood the ether with implementations. It should be used to absorb the chaos, structure a deterministic plan, and output artifacts that require near-zero cognitive load to review.

I know I don’t have this 100% figured out yet, but this is the protocol I’m building toward. Any feedback or criticism on this workflow is highly appreciated.

This is a good framing, and some of the work you mention here is mine, so I’ll add what we’ve learned running this at volume — many agents in parallel, across several repos, for months. All three of your rules survive contact with practice. Here’s what we had to add to make them hold.

  1. “Context before code” needs a why-document, not just history

Ingesting how everything is currently architected is the right starting point, but commit history and closed PRs tell an agent what happened, rarely why. The trap we kept hitting: you can get lost in what you think is an intentional decision, but it actually was a mistake — and vice versa. An agent will carry the mistake forward because it looks deliberate (what some people call “cargo-culting”), or “fix” a real decision because it looks accidental. Humans do this too; an agent does it at thirty files an hour.

What we landed on is a decisions record that lives in the repo: every load-bearing choice gets a short entry with the decision, the why, and what was rejected. Your rejected-proposals point is the underrated half of this — a recorded no keeps the same proposal from being relitigated by every fresh context. And it has to be required reading in the agent’s brief, not something it might stumble into. The repo has to carry the memory, because the agent doesn’t.

  1. Invariants first — yes, and raise the standard past the test itself

An isolated failing test is the right artifact, but for anything beyond pure functions it undersells what “reproducible” means. If the failure needs a database, a service, or a particular compiler build, the maintainer receiving the test inherits all of that setup. So the standard we hold: the invariant ships with any and all tooling that needs to be configured in order to reproduce it, and it explicitly states what versions were tested and how they were tested. Plenty of people run coding agents on their own machines, so you might be able to ask follow-up questions later — but it is not guaranteed that context still exists to retrieve next week. The reproduction has to travel with the submission, not live in a session that may be gone.

You’ve already seen this standard from my side of our own back-and-forth: on your router PR (amber #1391), the two behavioral divergences were reproduced against the exact original regex on Crystal 1.20.0 before I requested changes — pinned version, stated method. That’s the bar I want submissions to meet because it’s the same bar the review has to meet.

  1. Compliance shouldn’t be inferred — popularize the resources agents should refer to

This is the one I’d push furthest. “Match repository conventions perfectly” assumes the conventions are discoverable by reading the project — and in really large projects they aren’t, because there are lots of different patterns that conflict across various sections, built in different eras. An agent that infers conventions from code gives you whichever era it happened to sample.

What works: conventions written as explicit, versioned documents in the repo, scoped by directory where patterns legitimately differ, and loaded into the agent’s context before it writes anything. We run our projects this way — the conventions layer is called AED (Agent-Enhanced Development, GitHub - AgentC-Consulting/aed-conventions: Agent-Enhanced Development (AED): code conventions for codebases written, reviewed, and maintained by humans and coding agents together. · GitHub), and it works alongside FSDD (Feature Story Driven Development), which gives agents the intent behind a feature rather than just the diff. The measurable effect surprised us: these documents don’t let a less-capable model reason more, but they mean it can work with a larger amount of already-existing files and find details more quickly — and in practice that’s what lets smaller models get through longer workflows. I’d love to see the ecosystem converge on a standard place and shape for these files, the way we converged on shard.yml, so agent tooling picks them up with zero per-project setup. That’s the real road to your zero-friction integration: popularize the resources agents should refer to, instead of asking every agent to re-infer the criteria from the code.

  1. Estimate difficulty as vagueness, not effort

One convention that changed how we plan: we stopped estimating difficulty in time or headcount. With agents, labor is cheap and parallel — those axes stopped being the constraint. The measure of difficulty is the level of vagueness of the end goal, and the level of vagueness of the steps to take to get there. If I said “hey, work on the compiler and make it faster for native apps,” that’s very vague on the goal and very vague on how to get there — so it’s very hard. The more clear and measurable the end goal is, and the more the steps to achieve it are already provided, the easier the task is — even when the engineering underneath is identical.

Two consequences. First, your rules 1 and 2 are really de-vaguing machinery: context ingestion clarifies the steps; an isolated failing test converts a vague report into a measurable end state. Second, difficulty stops being something you estimate and becomes something you engineer down: when a task scores vague, the first deliverable isn’t code — it’s the artifact that removes the vagueness. A decision record. A failing test. A reference to match. A written acceptance bar. We have watched “hard” tasks collapse into easy ones the moment that artifact existed, and our worst weeks all trace back to building against a goal that only felt clear.

  1. The part your protocol implies but doesn’t say out loud: verification has to replace reading

The uncomfortable arithmetic is that agent-assisted volume outruns any maintainer’s ability to read everything. We stopped pretending otherwise. The scrutiny didn’t get lowered — it moved into tooling: the invariants we care about are enforced by static analysis and gates that run on every change, so the work gets the same level of scrutiny we’d apply to a human contributor, applied mechanically. Two hard-won rules from doing this: a gate must be non-vacuous — prove the gate itself can fail by feeding it a known-bad input, or you’ve bolted a green light to the wall; and a claim of “fixed” is worth nothing until a tool reproduces the before and the after.

This is also how your own amber PRs have been reviewed, so you can judge the style firsthand: #1385 was accepted only after the reflected-XSS was independently confirmed real against the actual error path; #1386’s code change was sound, but acceptance required the malformed-input specs and a corrected severity framing; and #1390 was caught as defined-but-inert — the new pipe was never wired into a pipeline, which only a “does this actually fire” check notices, never a read-through. Your protocol is asking agents to pre-clear that bar before submission instead of maintainers applying it after. I think that’s exactly right.

The agent’s job is to absorb the chaos. The project’s job is to hold the invariants, the conventions, and the decisions in a form that any context — human or agent, today or in six months — can load and be held to. The repos that thrive in this era will be the ones that are legible to a stranger with amnesia, because that’s what every new contributor context now is.

Happy to keep comparing notes on the Amber side of this. The conventions-as-artifact piece in particular feels ripe to standardize.

Hey @crimson-knight,

Your insights are spot on.

I’ve been testing these exact boundaries on my forks of crystal and shards using Google’s Jules coding agent to see what it takes to turn theory into a zero-friction maintainer experience.

Here is how we’ve operationalized these learnings:

Repository Memory (PJP)

To stop the agent from recurring rejected choices, we are using the Project Journaling Protocol (PJP) (gitlab.com/renich/pjp). We commit critical learnings and rejected proposals into version-controlled journal files under .agents/. The agent is instructed to read these journals before touching any code.

Eliminating Inference via Prompt Redirects

To prevent the agent from “cargo-culting” outdated patterns from different eras of the codebase, we moved all role-specific instructions into the repository (.jules/*_instructions.md). The web UI holds only a static pointer. The codebase’s rules of the road are version-controlled, not inferred.

The Token Economy

At the end of the day, we are trading tokens here. We pay for our tokens, and the last thing we want is to spend money generating noisy PRs that burn out maintainers. By combining PJP, strict local verification gates, and hyper-focused tasks (under 50 lines), we ensure that the tokens we buy are converted into verified, high-impact value for the community.

I will check out your AED conventions. Standardizing this layer is the key to scaling AI contributions without the noise.

Could you link one of these documents? I’m curious about what it looks like, but I can’t find it in the amber repo (after an admittedly quick look around).