Every spreadsheet for directory submissions starts the same way: one column called “status”, three values — todo, done, maybe “waiting” — and a total at the bottom that goes up every time somebody clicks submit. Two weeks later the total says 40, the number of listings a stranger can actually find says 6, and nobody can explain the difference without reopening every account.
The difference is not laziness. It is that “done” was asked to answer five different questions at once. This article is about those questions, why LaunchRepo’s tracker gives each one its own state, and two examples from our own seomap.dev run where a single “done” would have been wrong.
One column, five questions
When you submit a product to a directory, the people who care about the result want to know different things:
- Is the work done on my side? Did I fill everything in and press the button?
- Did the platform receive it? A thank-you page, an email, an entry in the account.
- Is it waiting for something? Moderation, a queue slot, an approval, a date.
- Can the public see it? A URL that loads for someone who is not logged in and does not carry a “pending” label.
- Do I need to do anything? A CAPTCHA, a two-factor prompt, a badge on my website, a decision about a paid route.
“Done” answers the first question and silently claims the fourth. That is how a total of 40 becomes a total of 6.
The states, and the question each one answers
The LaunchRepo tracker (record.py writing submissions.csv, and the same rules in the local dashboard) uses eleven states. Each is tied to a minimum observation — what you must actually have seen before recording it. Grouped by the question they answer:
Work on your side
- draft — preparation exists, the final submission was not confirmed. A saved form is a draft.
- prepared_needs_human — something precise blocks the prepared work and only a person can clear it: CAPTCHA, 2FA, an unclear account state. The note says exactly what.
The platform received it
- submitted_pending_review — the platform explicitly acknowledged receipt and moderation is still open.
- queued — the platform confirmed a queue position or a waiting-list state. Different from pending review: there is a line, and you are in it.
- scheduled — the platform confirmed a launch date on or after your earliest launch date. If approval is still outstanding, that goes in the note; the state stays scheduled.
The public can see it
- live — a public listing was verified, with no pending label. Requires the public URL and an explicit confirmation flag when recording.
- already_listed — an existing public listing was found and verified before you submitted anything. Same URL and confirmation requirement.
It stopped, for a reason you can name
- blocked — eligibility, account capacity or a mandatory fact you do not have.
- deferred_paid — the only usable route costs money; nothing was bought.
- not_a_fit — the product does not meet the directory’s audience or criteria.
- unavailable — the route or platform could not be used; the note records what was observed.
Eleven sounds like a lot. In practice each one exists because collapsing it into a neighbour produced a wrong report at least once.
Example 1: SaaSHub — public, but pending
SaaSHub’s submission, documented in the public SaaSHub field guide, produced a product page that was publicly reachable. Anyone with the link could open it. It also carried a visible label: Pending approval.
A one-column tracker records that as done, or even as live — after all, the page loads. The LaunchRepo rule is the opposite: public accessibility alone is not evidence of acceptance. The listing stays submitted_pending_review while the page says pending, and moves to live only after someone opens it again, sees no pending label and records the URL with the confirmation flag. In the SaaSHub case that meant the “live” count did not go up on submission day, and the follow-up file got a date to check back.
The extra detail the guide adds: domain-ownership verification on SaaSHub is a separate request from account login. That is a second thing that can be pending independently, and a note on the row is the right place for it.
Example 2: TinyLaunch — scheduled with approval outstanding
TinyLaunch, documented in the TinyLaunch field guide, offered a future weekly launch slot. The observed path went through a Standard launch, an optional-services step set to none, a scheduling confirmation and a second upgrade dialog with a “continue with free launch” option before the success page appeared. The dashboard then showed the confirmed date — and, next to it, Waiting for approval.
Two wrong ways to record this: live, because there is a date on a calendar; or submitted_pending_review, because approval is outstanding. The tracker records scheduled with the confirmed date passed explicitly, and keeps the outstanding approval in the note. Both facts survive: a date exists, and it may not hold. The zero-budget launch article covers the upsell part of that same flow.
This is also where the earliest launch date matters. product.json carries an earliest_launch_date; the tracker refuses to record scheduled with a date earlier than that. A solo developer who set the floor to “after the pricing page ships” cannot accidentally schedule a launch for tomorrow just because a directory offered the slot.
Three rules that fall out of the states
A thank-you screen is not live. It is, at best, submitted_pending_review. Most directories that review submissions manually take days to weeks; several free tiers in our run took longer than that. The status tracking guide is explicit that a long review estimate is neither a deadline nor a guarantee.
One submission is one row. Some directories offer a “also distribute to our partner sites” checkbox. Ticking it does not create a second submission until the second platform confirms receipt on its own. The tracker keeps one current row per platform and requires explicit replacement to change it, so a partner checkbox cannot quietly inflate the count.
Human handoffs are a state, not a failure. When an agent hits a CAPTCHA or a two-factor prompt it records prepared_needs_human with the exact next action and stops. The dashboard groups these under “needs you”. Marking them as anything else — retrying, “pending”, skipping — either evades a platform control or hides work you still have to do.
Why an agent needs this more than you do
If you submit to five directories by hand, you remember which one is pending and which one showed a calendar. An AI agent that runs a session, closes it and is restarted tomorrow — possibly a different agent, on a different machine — does not. It reads the tracker first and decides what to do from the state:
- prepared_needs_human and scheduled launches due for verification come first.
- submitted_pending_review rows whose review window has passed get rechecked — the existing record, not a new submission to jump the queue.
- live rows are left alone.
Every one of those decisions is wrong if the state is wrong. Recording live for the SaaSHub page would have meant nobody ever checked whether it was approved. Recording TinyLaunch as submitted would have meant nobody verified the launch on the confirmed date. The states are the agent’s memory, and the Claude Code walkthrough shows how a run reads them at the start of every session.
What a good report looks like
Instead of “40 done”, the dashboard shows something like: 6 live with public URLs, 21 pending review with check-back dates, 4 scheduled with confirmed dates, 3 need you, 2 deferred because the free route did not exist, 4 not a fit. The total is still 40. Every number can be defended, and each group has an obvious next action.
That is all a tracker is for. Not to look impressive — to tell the next person, or the next agent, what is true and what to do.
If you are setting up your own run, how LaunchRepo works shows where the tracker sits in the workflow, the SaaS founders page covers the setup for a product with a real launch calendar, and the pricing page has the one-time licence for the repository the tracker ships in.
Sources: RUNBOOK.md and AGENTS.md in the LaunchRepo repository (state table and minimum observations), the public SaaSHub and TinyLaunch field guides (observed 2026-09-13) and the submission status tracking guide. The report numbers in the last section are illustrative, not measured.