Bruto - A task board that lives in your repo, for you and your AI

by•
A brutalist task board for coding with AI. Notes live in your repo: copy the context with one key, or let an agent work the board over MCP and answer in each note. Standing rules, cross-project links and a map of your pages, APIs and tables. Free, open source.

Add a comment

Replies

Best
Maker
📌
Hi Product Hunt 👋 I built Bruto because working on a project with an AI meant explaining the same things again and again, in a chat that forgets. My tasks lived in one place, the context in another, and the AI's answers got lost in old conversations. Bruto keeps a project's tasks as notes in a file inside the project itself (.bruto/workspace.json), so you and every AI you use work from the same source: 1. Write tasks on the board: what's wrong, which files, links, screenshots. 2. Copy exactly the context the AI needs with one key (Q, W or E): clean Markdown with short instructions for the model, and a preview of how many tokens it is. 3. If the AI can edit files (Claude Code, Codex, Cursor…), it answers inside the note and marks it for review. Bruto picks up the change live. If something is still wrong, write what and send it back with all its context. A few things I cared about: • Local only: no account, no server. Your notes never leave your folders, and it works offline. • Safe with other tools: every save merges changes made elsewhere, note by note, and never overwrites a broken file. • Standing rules: a note marked "Loop" ("run the tests before finishing") goes into every copy. • It draws your project: pages with their components, API endpoints and database tables, with your notes on top. It's free and open source (MIT). Opening your own folders needs Chrome, Edge, Brave or Opera on a computer, but you can look around the example project first, right in your browser: I'd love to know how you keep track of tasks when you code with AI, and what would make Bruto fit your workflow.
💎 Pixel perfection

We came to the same approach too. We create a markdown file for each task. At the start we write the status and state. The approach is simple and works fine. I ran through your code because I was curious how you do the sync. And I think I found a possible problem there. The sync itself works well and is written carefully, but there is this scenario. Say we have an unsaved change to a note's state locally. At that same moment the AI agent changes the state of the same note. Then the local copy wins and rewrites the file. And it all looks fine. But the problem is that the AI agent thinks everything went through and that it made the change. And the log will say so. No errors. But in fact it's not true. How do you feel about adding a short line at the top, like "state was changed back"?

 Great catch, and thanks for reading the code that closely. You were right: with an unsaved local edit, an agent's change to the same field was overwritten and nobody was told. Fixed and shipped: the human's value still wins, but now the note opens with a line telling the agent its change was reverted (so it sees it on its next read), the audit log records it, and the user gets a notice with "Use theirs". Both writers also re-read before writing now, so neither overwrites a save that lands in between. Markdown per task is a nice approach too, simple wins.

 If you'd like this to count on Hypership, feel free to log it as a fix: it's live in the app and in bruto-mcp. I'll mark it complete with the details. Thank you.

💎 Pixel perfection

One from building a board like this: keep a task's age when it changes hands. On mine a task passed to someone else keeps its clock, otherwise something bounced back and forth for a week always looks like it arrived today. A small "sent back 3 times" on the note would do a lot of it here, since the round trip with the AI is the loop that repeats.

 Thanks Dale, that's a good one, and it's in. Every note now keeps its age from the day it was made, whatever status or hands it passes through, and counts each time review sends it back to the AI: the card shows "6d ↩ 3". The AI sees it too ("sent back 3 times") when it picks the note up, so it knows it's not the first round.

 Nice, "6d ↩ 3" is exactly what I'd want to see on the card.

 Tried it on the example board, sent Cancel a booking back and it went to ↩ 2 while staying at 6d. Works.