Abdulkader Safi

Tagging 1.0.0 with four features missing, on purpose

The gate list had thirteen items. Six went in, seven did not, and the tag went out anyway. What the number promises is that the API stops moving, not that the feature list is finished, and conflating those two is how packages sit at 0.x for three years.

4 min read

Share
A version number changing from 0.5.0 to 1.0.0 beside a list of deferred items.

Atelier went 0.1.0 to 1.0.0 in four weeks and eleven releases. The last one was mostly a decision.

The two bars people confuse

Docs/tasks/14-v1-release.md was written on 3 September specifically to keep them apart.

The product bar is the eleven success criteria in the PRD. Drag to reorder was the last unmet one, and it landed in this release.

The package bar is what 1.0.0 promises a stranger who runs composer require: a named public API, a support matrix CI actually tests, a suite that runs from a clone, and documentation that is true.

Below 1.0.0 a minor release may break anything, and the changelog says so. That freedom is worth having while the shape moves and worth losing once client projects depend on it. So the cost of tagging too early is one specific thing: a rename inside Block, AtelierPlugin or the config keys becomes a 2.0.0 instead of a footnote.

Which means the tag is a statement about names, not about scope.

What the number actually covers

A table in the README, because a promise nobody can read is not a promise:

  • Block and BaseBlock, PageType and BasePageType
  • AtelierPlugin's registration methods
  • The documented methods on Page, plus Media, Tokens, Url, MenuSource
  • Two head partials, and data-atelier-canvas as the layout contract
  • Every key in config/atelier.php
  • Column names and shapes in six tables

And, just as importantly, what it does not cover: the registries, everything under src/Filament/ and src/Http/, the renderer, the shared controls. Those are internal and free to move in a minor. Naming the internals is what stops a 1.0 from freezing the whole codebase by implication.

What is missing, and why it did not block the tag

Four blocks from the v1 scope do not exist: header, footer, contact form, raw HTML.

Header and footer are arguably answered by layouts plus the menu manager, which arrived after the list was written. The honest move is to strike them from the PRD with a dated banner, and I have not done that yet, so they stay listed as owed.

The contact form is blocked by an open question that has been open since August: where a submission should land. A table, an email, a CRM. A package that picks one is wrong for most projects, and one that supports all three has a configuration surface bigger than the feature. The example app now ships a working one written in the host app, which is the shape the answer will take.

Raw HTML is the genuinely missing one, named in the project's own non-negotiables as the escape hatch for one-off markup. It is an afternoon. It did not happen this week.

Also deferred: Core Web Vitals were never measured, per-block asset loading does not exist, there is no revisions UI, and the menu manager still ships behind an experimental flag, which means the criterion it satisfies is met by a feature nobody sees by default. That criterion moves to 1.1 rather than being called met.

Saying it out loud is the whole trick

All of that is in the release notes and in the gate file with dates. Not because transparency is a virtue in the abstract, but because deferred and forgotten look identical from outside a repository, and the difference is exactly what someone deciding whether to depend on your package is trying to work out.

"Not built yet" in the README is a section I have kept accurate since the first release, and it is the part I would keep if I could only keep one.

The bit I would do differently

I tagged 0.5.0 four hours before 1.0.0. Two releases in a day, because page types felt like a version and then the editor work felt like a version, and the number in between never reached anyone.

The honest version is one release with both in it. The changelog is right either way, but a version nobody installed is bookkeeping rather than a release.

Where it stands

v1.0.0, on Packagist, with 232 tests, a wiki that matches the code and a demo site you can click through end to end.

Not finished. Named.

Last updated 13 Sep 2026 · filed under Laravel, filamentphp, plugin, tools, web application

Every entry on this project

28 build notes, in order

Including the ones where nothing worked. You are on part 28.

Read the series →

FAQ

Frequently asked questions

What should a 1.0.0 version number actually promise?

That the public API stops moving without a major bump, and nothing else. Semantic versioning is a statement about compatibility, not about completeness, so a small but stable package is a perfectly honest 1.0 and a huge unstable one is not. The work before the tag is therefore mostly naming: writing down which classes, methods, configuration keys and file contracts are supported, and which internals may change freely. Without that list, a 1.0 accidentally freezes everything anyone happens to be calling.

Should you delay 1.0.0 until the planned feature list is complete?

No, and packages that do tend to sit at 0.x for years while people depend on them in production anyway, which is the worst of both. Ship the tag when the interface is settled, keep an accurate list of what is not built, and add features in minor releases. The real risk is the opposite one: tagging while a public name still feels wrong, since renaming it afterwards is a major version or a deprecation cycle.

How should a release communicate deferred work?

By name, with the reason, in the release notes rather than only in an internal file. From outside a repository, deferred and forgotten look the same, and someone evaluating whether to depend on your work is mostly trying to tell those apart. Saying "this is not built, here is why, here is what would trigger it" costs a paragraph and answers the question directly. Keep the same list in the README so it stays visible after the release notes scroll away.

Is it a problem to tag two releases in one day?

It is not harmful, but it is usually bookkeeping rather than releasing. A version that nobody installs before the next one lands exists only in the changelog, and each tag carries real costs: notes to write, a migration path to describe, and a support surface to remember. Group the work into a release when it is genuinely usable together, and if you catch yourself tagging twice in an afternoon, the earlier one probably wanted to wait for the later one.

Written by

Abdulkader Safi

Software Engineer

Lead engineer at DSRPT, from Lebanon and based in Kuwait. I write about the tools and bugs from real client work, with the numbers I measured.

About me → GitHub LinkedIn

Need this kind of work done on your project?

Start a project →

Keep reading

More from Filament Atelier

All 28 entries →