I tested the Projects beta for three days: what worked, and where decisions got lost

I tested the Cursor Projects beta for three days on a real side project: five sessions, about fourteen hours, twenty agents, 32 tasks and five PRs, four of them merged. Model on Auto, Pro plan, no rules, skills or custom prompts. The result, an ioBroker adapter, now runs on my home server.

What worked

I like the approach a lot. One orchestrator that keeps the context and hands the work to agents works better than a row of isolated chats. Delegation worked, and the agents delivered. Every one of the 49 agent turns sent a completion event to the orchestrator, including the ones I had started by talking to an agent directly. Codex, an external review bot I had set up on GitHub, left 18 findings across four PRs, and all 18 were fixed. The overview of agents, PRs and subscriptions at the bottom of the chat is very handy, and in the evenings I checked PR status from the couch in the iOS app.

I exported the orchestrator chat, the agent threads and the context folder, and checked my impressions against that record. Three things kept coming up. None of them is really a bug. They are about decisions, and I would want them solved before using Projects on professional work.

1. The notes are written, but rarely read

The Project Notes, a short index of the current work with an archive for finished items, were written 111 times and explicitly read once. The archive only started on day two. Milestone 1 had already been deleted from the notes and never made it there. From milestone 2 on, finished work was archived. A decision I had made early on (I had the podcast’s approval for the LLM analysis) dropped off the short list after two rewrites. The next day it came back as an open blocker, and I confirmed it a second time.

It got worse with a handoff. An agent handed work to the orchestrator, and the orchestrator did it. When I asked, it first said yes, then said it had never received it. It then wrote that wrong account into the context folder as a workflow rule, which the next agent read.

Suggestion: an append-only log of decisions and events that the orchestrator reads at the start of every turn.

2. Defaults get treated as approved

I asked “ok, so we can start with M2?”. The assignment to the agent then said the defaults were “accepted for the start”. I had not accepted any. In another case the orchestrator itself recommended no permanently running process, and the agent delivered an always-on adapter with its own cron library. I usually found out when I looked at the result.

Suggestion: the same log, with a clear difference between “decided by the user” and “picked by an agent”.

3. Unclear responsibility for review comments

Several parties could react to the same review comments: the orchestrator, the agent that built the PR, or a new agent started just for the fixes. Who acted depended on who happened to be subscribed. On one PR the orchestrator asked me twice about fixes the agent was already making. On others it forwarded them without asking. Comments from a second review bot were ignored, which was right, but I could not see that anyone had looked.

Suggestion: one owner per PR, including its review comments. If a comment is dismissed, the reason goes into a file. A context folder under git, with one commit per milestone, would also show who changed what. One status file was rewritten by three agents and ended up with the wrong author.

Beta rough edges

These I would expect in a beta, but they might help:

  • Running agents on my own machine did not work on Linux right away. The command the orchestrator gave me did nothing. The docs say agent login, then agent worker start in the repo root. In the end, everything ran in the cloud.
  • “Take Control” on an agent’s cloud desktop did not work on Linux. I could not move the mouse inside it.
  • Completion events reach the model but not the chat view, so I could not see what the orchestrator had received.
  • A terminal is only available for the orchestrator, not for the other agents.
  • One link in the notes pointed nowhere.

Full write-up with screenshots and the original quotes: https://dev.to/lutz_leonhardt/cursor-projects-a-plan-rewritten-111-times-and-read-once-4j77

I will keep using Projects, especially for side projects. Happy to share more details if that helps.

Thanks for writing this up with the export evidence — the “notes written 111× / read once” and the podcast-approval decision that fell off the short list then came back as a blocker are painfully familiar.

Your user-vs-agent polarity is the load-bearing distinction. A pattern that usually holds up better than a mutable notes index:

  • Treat every consequential choice as an append-only event, not a field that gets rewritten.
  • Agent conclusions stay proposed until the user explicitly accepts them; silence is not acceptance.
  • When something changes later, emit a supersedes event that points at the prior one instead of editing history.
  • Persist at least: author (user vs agent), source turn/session, status (proposed / accepted / superseded / rejected), and a one-line reason.

That would have caught both the early approval that vanished after rewrites and the “defaults accepted for the start” assignment you never made.

Quick question for the Projects surface: do the orchestrator / agent turns expose stable event or turn IDs you can cite later? Without those it is hard to prove a decision was rewritten versus merely dropped from the current view — and hard to teach the next agent which polarity a line actually has.

Curious whether that matches what you saw in the exported context folder, or if Projects already has an ID you could hang an append-only log on.

Short answer: no. One thing first: Cursor has no export for Projects. I used “copy thread” on the orchestrator and on each agent, and took a snapshot of the synced context folder.

In that copy, agents have an ID and a URL, and the notes link to them. GitHub events land in an inbox folder with an event ID and a millisecond timestamp. Completion events have a timestamp to the minute and the agent ID. My messages, the orchestrator’s messages and every edit to the notes have neither ID nor timestamp. Tool calls have an ID that repeats within one orchestrator turn, so turn IDs exist somewhere. They are not on anything I can see.

Rewritten or dropped: I could only see the difference because the orchestrator’s edit tool writes the whole notes file every time, so the chat copy holds all 111 states. The approval was a note on a ticked item. It was there in two states. In the third it was cut to “done”. The item stayed, the fact went.

“Who decided what” is recorded nowhere. The approval reached the orchestrator inside a completion event that quoted my message to the agent word for word. The note it wrote does not say so. The cron library is the clearest case: the agent picked it, I asked why, and then had it written down as a decision. The plan now says “decided”, with no trace that this came after the fact.

One thing I should add to my post. Before I asked “can we start?”, the orchestrator had listed the defaults and asked me to confirm them, five keywords and three open questions. I asked about the API key instead, then whether we could start. Its reply named the defaults and started the agent in the same turn. So they were on screen, but nothing in between was a yes.

Really useful teardown. The approval getting cut to “done” is the one that hurts. One thing that helps: split the notes in two. A plan file the orchestrator is free to rewrite, and a decisions.md in the repo that is append-only. Each entry gets a date, who decided (you or which agent) and one line of why, and a rule tells agents to add entries and never edit old ones. Your cron library case then reads “agent picked X, confirmed after I asked” instead of just “decided”. Git history gives you the timestamps the export doesn’t.

Madhur’s split (a plan file the orchestrator can rewrite, plus an append-only decisions.md) is the right base. Two things made the bigger difference for us once the log grew past a few dozen entries:

  1. Scope each decision to paths. A flat decisions file gets read once at the start of a session (your “written 111 times, read once” problem) and then fades out of context. If every entry carries the globs it applies to, the agent can pull just the relevant ones when it touches those files. In plain Cursor you can get close with one .mdc rule per decision and globs set, instead of one big always-on file.
  2. Check at review time too, not just at write time. The approval that quietly became “done” is exactly what an agent won’t notice on its own. A PR check that compares the diff against the decision log catches it after the fact.

I’d also keep your user-vs-agent polarity as fields on every entry (decided_by: user | agent, status: proposed | accepted | superseded). It’s the only way to tell later whether something was decided or just assumed.

Disclosure: I’m a co-founder of Tently, which automates this (it mines decisions from PRs and reviews, gives them to the agent over MCP, and checks PRs against them). But the decisions file plus path-scoped rules gets you most of the way without any tool.

One more thing for the append-only decisions.md: give each entry a pointer to the commit or file it changed, and have a new agent check those pointers before it acts on the log. A short list that can be checked gets read at the start of a session; a long one that can’t mostly doesn’t, which matches your “written 111 times, read once”.

I’ve been doing this in Claude Code with a plugin I maintain (Succession, free, MIT), but the idea works with any agent: GitHub - thecontinuitylayer/succession: Your AI gets a name, a job, and a successor. Claude Code plugin: named sessions, checkpoints, handoffs checked against git. · GitHub