This slate has a second page. It is in the navigation, and it exists only to prove this sentence.
Files Become Pages
A slate synced from a repository is a folder with a .slate file and a pages directory. Every .chext file directly inside that directory becomes a page. There is no manifest, no ordering file, no configuration. The filenames are the structure.
my-slate/
.slate
assets/
pages/
Home.chext
Roadmap.chext
changelog.chext
about-me.chext
Home Is a Convention, Not a Flag
There is no root page column and no special case for Home.chext in the sync code. When a slate is created the platform makes one page titled Home. When the sync walks the pages directory it converts each filename into a title and looks for an existing page whose title matches, ignoring case. Home.chext matches the page that was already there. That is the entire root mechanism.
private String toPageTitle(String pageName) {
var words = pageName.replace('-', ' ').replace('_', ' ').trim().split("\\s+");
var sb = new StringBuilder();
for (var word : words) {
if (word.isEmpty()) continue;
if (sb.length() > 0) sb.append(' ');
sb.append(Character.toUpperCase(word.charAt(0)));
if (word.length() > 1) sb.append(word.substring(1).toLowerCase());
}
return sb.isEmpty() ? pageName : sb.toString();
}
Which Means Your Casing Is Gone
Hyphens and underscores become spaces, every word gets a capital first letter, and everything else is lowercased. about-me.chext becomes About Me, which is the intended behaviour. APIReference.chext becomes Apireference, which is not. The write-back is narrower than it first looks. It only fires when the stored title and the filename still normalise to the same string, so a casing tweak gets reverted. Rename a page properly in the editor and it no longer matches, so instead of being overwritten you get a second page alongside the first.
Pages on this slate
2
Maximum pages per slate
no limit
Page title column
varchar 50
Ordering column
none
Nested directories under pages
ignored
The Ordering Problem
Pages are fetched with no order clause at all. What you see in the navigation is insertion order, which on a first sync comes from iterating a hash set of filenames. It is stable once created and arbitrary when created. There is no reorder control in the editor and no way to express order from the repository. Moving a page up means deleting it and making it again. This is the single weakest part of the feature and it has been that way since it shipped.
What a sync does to each changed page
Compares the file hash against the last synced hash
Fetches only the files that changed
Deletes every chip on the page and rewrites them in file order
Publishes the page immediately
Deletes pages whose files were removed, except Home
Warns you about .chext files in subdirectories
Truncates a filename longer than the 50 character title column
That Last Box Is Not Cosmetic
A page filename that produces a title over fifty characters fails the insert, and the failure takes the whole folder sync with it, not just that page. The guard is one truncation call that has never been written.
The Slate Chip
The other half of nesting is a chip that points at a different slate. You give it a numeric slate id on a single line. It renders as a card with the target slate's banner, name and author, linking out in a new tab. It is deliberately not an inline embed: two full slates rendered inside one another is a scrolling problem with no good answer, and a card is honest about being a door rather than a room.
:SLATE
1042
A Numeric Id Is a Real Limitation
Not a handle, not a slug, a database id. Which means a chext file that references another slate is not portable, cannot be written before the target exists, and cannot be read by a human as anything but a number. A slug form would fix it. Nobody has built one.
And a Bad Id Fails Everything
On write the chip resolves the target and checks that the author can view it. If the slate is deleted or not viewable, that throws, and the throw happens during persistence, so the entire slate fails to sync. Not the chip. The slate. On read it is gentler: a viewer without permission simply sees nothing where the card would be. Two different failure philosophies in one chip, which is at least defensible: the author should find out loudly, the visitor should not be shown an error they cannot act on.
Two Slugifiers That Disagree
The app builds sub-page links by lowercasing and replacing spaces. The server resolves them by lowercasing and replacing every run of non alphanumeric characters. For plain titles the two agree. For a title with an apostrophe, a full stop or an accent they do not, and the result is a link the app happily renders and the server cannot resolve. Two implementations of one rule, written months apart, in different languages. It will keep happening until one of them is deleted.
"Structure that lives in filenames is structure you can read with ls.
"
