TaskFlow
A team task board you can run from a web page or from Claude and ChatGPT. Remix it into your own Dodil organization and it comes up live with its tables, sign-in and AI.
"What's on my plate this week?" · "Add a card 'Send invoice' to Doing on the Ops board" · "Move card 12 to Done" · "What's overdue?" · "What is blocking the launch?"
Built for the Dodil Boards Challenge. MIT licence.
What it does
| Area | What you get |
|---|---|
| People | The owner invites people as member (can edit) or viewer (read only), changes roles and removes people. Removed people's cards become unassigned. |
| Boards | Boards → lists → cards. Default lists are To do, Doing, Done; the owner can add more (new lists go before Done). The list called Done means finished. |
| Cards | Numbered per board (#12), with title, description, assignee, due date, labels, a checklist and "blocked by" links. Drag and drop between and within lists. |
| History | Every change is recorded: who, when, and exactly what changed ({"list_name": ["To do", "Done"]}). Per card and per board. |
| MCP | 26 tools for Claude/ChatGPT, all actions, no table access. The assistant sees only the boards its signed-in person can see. |
| AI (Dodil Models) | "Turn this card into a checklist", "find cards like this one" (embeddings), and a daily board summary. |
| Overdue | Cards past their due date and not in Done are flagged on the board and listed under Overdue. |
| Dependencies | "Blocked by" links with loop protection, and "what is blocking X?" walks the whole chain. |
| Tidy up | Delete cards (they stay in the history), rename lists, delete empty lists. The owner deletes a board from the web page only, by typing its name: no assistant can wipe a board. |
Remix it
dodil update # CLI 0.1.89 or later
dodil git remix <org>/taskflow --to-org <your-org> --name <your-repo> # repo name: 18 chars max
The remix creates the repo, a DataK3 bucket <repo>-data with the tables from schema.sql, a
user pool <repo>-users, and a service account with access to the bucket and Dodil Models.
CI then tests, builds and deploys it to Ignite.
After the remix: let people sign in
-
Callback URL. The deploy registers
https://<app host>/.dodil/auth/callbackon the pool itself; its log says "already lists the sign-in callback". If it says "not registered", run the command that line prints, once (dodil guide remix, "After the remix: let people sign in"). -
Recommended: verified emails. Boards are shared by inviting an email address, so make people prove they own the address they sign up with. Otherwise someone could register an invited address before its owner does:
dodil appid settings set <repo>-users --require-email-verification
Then open the app URL, sign up, and create your first board.
Use it from Claude or ChatGPT
Tested end to end with Claude.ai (custom connector). ChatGPT speaks the same MCP and OAuth standards, but I haven't been able to test it.
The app serves MCP at https://<your-app-host>/mcp. Add it as a custom connector. It asks you to
sign in through the pool; approve the client once:
dodil appid client list <repo>-users
dodil appid client approve <repo>-users <client-id>
If Claude.ai says "Couldn't register with TaskFlow's sign-in service" (we hit this while
testing; the self-registration request never reached the pool), skip self-registration: register
Claude as a first-party client once, then in the connector pick Use your own OAuth client
with client ID claude-ai and no secret.
dodil appid client register <repo>-users --client-id claude-ai --name Claude \
--redirect-uri https://claude.ai/api/mcp/auth_callback \
--redirect-uri https://claude.com/api/mcp/auth_callback --yes
Then just talk to it. Boards can be named by title ("the Ops board") and cards by number ("card 12"). If two of your boards both have a #12, it asks which board you mean.
| Ask | Tool it uses |
|---|---|
| What's on my plate this week? | my_cards(due_within_days=7) |
| Add a card 'Send invoice' to Doing on the Ops board | add_card |
| Move card 12 to Done | move_card |
| What's overdue? | overdue |
| Give #4 to bo@example.com, due Friday | assign_card, update_card |
| What is blocking the launch? | what_blocks |
| Turn card 7 into a checklist | checklist_from_ai |
| Anything similar to #9? | similar_cards |
| Summarise the Ops board for today | board_summary |
| Who changed card 3? | card_history |
Run it locally
cd app
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt pytest
cd .. && python -m pytest -q tests # no Dodil account needed: in-memory data and AI
To run the server against your remixed bucket, set BUCKET, DODIL_SERVICE_ACCOUNT_ID,
DODIL_SERVICE_ACCOUNT_SECRET and DEV_USER=you@example.com (acts as that person without the
gateway; local only), then from app/:
uvicorn taskflow.main:production_app --factory --port 8080
How it's built
app/taskflow/
domain/model.py Board, Card, Role and every rule (plain Python, no I/O)
application/use_cases.py every action; the only thing the doors call
application/ports.py what the use cases need: a repository and an AI assistant
infrastructure/ DataK3 repository, service-account token, Dodil Models client
doors/web.py, page.html JSON routes and the board page -> use cases
doors/mcp.py MCP tools for Claude and ChatGPT -> the same use cases
doors/identity.py who is calling (the gateway's X-Dodil-User header)
main.py wires it together: /mcp, sign-in metadata, /healthz
tests/ the rules, through the use cases and through both doors
schema.sql the tables, created by the remix
.dodil/remix.yaml what a remix creates
.dodil/deploy.yaml how CI deploys every copy
Design decisions are in DESIGN.md.
What I'd improve next
- Edit conflicts: if two people edit the same card at the same moment, the last save wins. A version number on each card (409 "changed since you opened it") would catch that.
- Real-time updates on the page (today it refreshes after each action).
- Store embeddings in DataK3's vector search instead of computing them per request, so "find similar" scales past a few hundred cards.
- Comments on cards and @mentions.
- Archive instead of delete, and a board-level "archived cards" view.