Two JSX props are the entire interface of Coframe coffee
Build and iterate on your UI 10x faster with AI - right from your own IDE ☕️
At a glance
- What is it?
- Coframe coffee is a Docker-wrapped Python agent that watches js, jsx, ts and tsx files, finds components carrying a Coffee or coffee prop, and sends parent code, child code and prompt to the OpenAI chat completions API. The loop is small and readable, and the project's own task list contradicts several of its feature claims.
- Who is it for?
- Judge coffee on the loop it actually implements: two JSX props, a file watcher, and a rewrite that only becomes permanent once you add pour. It fits a React codebase where you want to describe a component and iterate on the wording of a prompt, and it fits teams already running their own formatter and CI.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 97 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The whole interface is a file watcher plus two JSX props
coffee runs as a container beside your app and never touches your build tooling. It listens for changes to js, jsx, ts and tsx files in your source directory, and its only trigger is a JSX prop. One form, `<Coffee>`, creates a component. A second form, a `coffee` attribute on a component that already exists, edits one. Files without a marker are read as context but never rewritten.
The container bind mounts the working directory at /mount and reads OPENAI_API_KEY from the environment:
docker run --pull=always -it -e OPENAI_API_KEY=${OPENAI_API_KEY} -v $(pwd):/mount coframe/coffee:latestThe stated workflow has no dependencies and no setup: your React app runs the way you already run it in one shell, while the container runs in a second shell in the same directory. You can also build the image yourself from the repository's react directory:
./dev.sh build
OPENAI_API_KEY=your_api_key ./dev.sh ../path/to/any/frontend/repo/on/machineThe claim that you do not need to touch Python holds, but it is narrower than it sounds. Adding a `coffee` attribute still means writing a string into your own source file, and the cleanup step at the end means editing that file again.
Every save puts parent code, child code and prompt into chat completions
The trigger fires on each save, but not for every component. coffee marks a component as needing brewing only when it is new, or when its props or its prompt text have changed. That check is what keeps a no-op save from producing anything.
When it does fire, the request to the OpenAI chat completions API carries four things: the code of the parent component, the code of any existing child component, the prompt written between the JSX tags, and whatever custom configuration is present. The prompt is ordinary text, so the project expects you to apply your usual prompt techniques to it:
<Coffee parameter={parameter}>
Here is where you put your prompt that Coffee will use to generate the first
version of your desired component. This is the same type of prompt that you'd
use with any LLM like ChatGPT, so feel free to get creative and apply your
favorite prompt engineering tricks. Finally, you can also pass in any
parameters you want from your parent component by simply adding them as
demonstrated above.
</Coffee>Passing `parameter={parameter}` in is how you forward values from the parent at generation time. The cost profile follows from that design rather than from any tuning: every prompt edit is a fresh completion request that carries the surrounding component code along with it.
The first save leaves your app broken until the agent finishes
There is a rough edge in the loop, and it is stated rather than hidden. Because the generated component does not exist until coffee writes it, your application can throw an error the moment you save a file that introduces a `<Coffee>` component for the first time. The project calls this normal and says it clears once the agent has had time to brew the component.
That is a direct consequence of keeping generated code out of your tree until you ask for it, and it collides with the fact that the tool reacts to saves. A first save compiles into a broken state, the container generates the file, the editor rebuilds, and the error disappears. Any pipeline that treats a compile failure as fatal stops somewhere in that window.
The same shape applies to edits. To change a component that has already been brewed you replace the prompt text with the change you want, for instance making a button background darker. To change a component that is already plain React, you add the `coffee` attribute instead:
export function Example() {
return (
<MyButton
title="Click Me"
onClick={() => console.log("clicked")}
coffee="make the button color blue"
/>
);
}Once the change lands, removing the attribute leaves ordinary code behind.
pour is the only step that writes a file you keep
Generated code stays inside the JSX tags until you name a destination. Adding a `pour` prop gives the component a filename, and saving the file replaces the whole `<Coffee>` block with a normal import and usage:
export function Example() {
return (
<Coffee
title="Click Me"
onClick={() => console.log("clicked")}
pour="MyButton.tsx"
>
Whatever you prompted Coffee to generate
</Coffee>
);
}Saving that file rewrites the example to:
import MyButton from "./MyButton";
export function Example() {
return <MyButton title="Click Me" onClick={() => console.log("clicked")} />;
}The filename is relative to the importing file, and the rewrite is mechanical: the import name comes from the file, and every prop you passed, including `pour` itself, is carried across. That is the point where output leaves the loop and becomes source you can review, refactor and commit. Until you add the prop, the component exists only in the tags and regenerates on every prompt edit, so pour is also the boundary between throwaway output and code that enters your repository.
The feature list and the task list disagree about four promises
The project advertises code that is clean and maintainable, and in the same document carries an unchecked box for running prettier on generated code. Nothing in the documented workflow formats the output: pour writes the file the agent produced, and no step between generation and disk reformats it. If your repository runs a formatter in CI, the first pour produces a diff that formatter wants to change.
Three more unchecked boxes undercut claims made earlier. Custom prompts are unfinished even though the prompt between the tags is the primary interface. Custom agents are unfinished even though the workflow description assumes one agent. Wider support for a coffee.config.json config is unfinished even though the request payload is described as carrying custom configuration. Native integration with Next.js, webpack, Remix, Prettier and ESLint is unfinished, while the feature list says the tool works with any React codebase including Next.js and Remix. Reading and writing through your editor and a file watcher is not native integration, but the two statements sit close enough to mislead a reader deciding what works today.
The one checked box is the item that lowers risk: basic tests and GitHub CI.
No releases, and the image is always the newest tag
The project publishes no GitHub releases. What consumers actually run is the Docker image, and the documented command pins nothing: the tag `coframe/coffee:latest` together with `--pull=always` means two runs a week apart can execute different code with no version to return to. The dev.sh path is the only way to fix what you execute, and even there the artifact is whatever your local build produced. The last commit on the default branch is dated 2026-06-28.
The top level of the repository is short: .editorconfig, .github, .gitignore, CODE_OF_CONDUCT.md, LICENSE, README.md, _roastery and react. react is named as the directory to build from. The name _roastery appears nowhere in the documentation, so the coffee metaphor extends past what the document explains.
The implementation is Python. Docker is credited with making sure that any agentic code it runs is fully isolated, and the same command bind mounts your working directory into the container, so the isolation covers the agent process while pour still writes into the real tree.
The session has a fixed shape and the bookkeeping is manual
A complete run through the tool has a predictable sequence: add `<Coffee>` with a prompt, wait out the first save error, edit the prompt until the component looks right, add pour to write the file, and drop the marker attribute when you are finished editing it. Nothing marks which files still carry a marker prop, and nothing reports which written files have drifted from the prompts that produced them. With several brewed components in one codebase, that accounting stays in your head.
Iteration is described as something you can do indefinitely, and the mechanism supports that, since any prompt text can be replaced. Each replacement costs another completion request carrying the parent and child code with it, and the project's own description of the brewing step calls it a little slow while listing faster agents as unfinished work.
What the tool does is narrow and real: two props, a watcher, and a mechanical rewrite. What it leaves out is formatting, file bookkeeping, configuration beyond the basics, and any framework outside React.
Editorial conclusion
Judge coffee on the loop it actually implements: two JSX props, a file watcher, and a rewrite that only becomes permanent once you add pour. It fits a React codebase where you want to describe a component and iterate on the wording of a prompt, and it fits teams already running their own formatter and CI. Before adopting it, fix what you execute, because the documented command tracks a moving latest tag and the project publishes no releases, and budget for a slow first generation on every prompt edit.
Frequently asked questions
Does Coframe coffee need a package installed in my React project?
No. The stated workflow runs your React app as you normally would and starts the container in a second shell in the same directory, bind mounting that directory at /mount.
How do I make Coframe coffee write the component to a real file?
Add a pour prop carrying a filename, for example pour="MyButton.tsx", and save. The JSX block is replaced with an import from ./MyButton plus a usage line.
Why does my app throw right after I add a Coffee component?
The generated component does not exist until the agent writes it, so the first save can leave the app in a broken state. The project calls this normal and says it clears once brewing finishes.
Does Coframe coffee run prettier on the code it generates?
Running prettier on generated code appears as an unchecked item in the project's own task list, so the documented workflow leaves formatting entirely to your own tooling.
Can Coframe coffee edit a React component that already exists?
Yes. Add a coffee attribute holding the description of the change, save, and the component is regenerated. Remove the attribute once you are satisfied with the result.
Which frontend frameworks does Coframe coffee support?
The feature list says any React codebase including Next.js and Remix. Vue and Svelte appear as unchecked items, next to native integration with webpack, Remix, Prettier and ESLint.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/coframe-coffee)