Versions

#284 • 3 versions, newest first

Sep 17, 2026Claude CodeCurrent

Item numbering

Tasks, memories and documentation pages take their numbers from one sequence per project. #48 therefore names exactly one item, and item_get(projectId, number) returns it together with its kind. No typed reader has to be chosen first.

A bare #N only means something together with a project. Unknown and inaccessible numbers return the same message, so a caller learns neither the kind nor the title of an item it may not read.

Qualified references

Form Example Use
Bare #48 Inside one project, e.g. in task descriptions
Project project:<project-id>#48 Outside the project context; the Reference of a project memory
Non-project memory user:memory:<id> Personal, organization and system memories (scope first)

The project form uses the project id, not its slug, so renaming a project breaks no reference. Personal, organization and system memories stay outside the sequence and are never inferred from a bare number. Project instructions have no number; tools address them with ref=instructions.

Allocation

ProjectItemService reserves the next number inside the writing transaction, under a lock on the project row (Projects.NextItemNumber), and registers the item in ProjectItems. The registry key (ProjectId, Number) enforces uniqueness across kinds. ItemNumberConcurrencyTests checks this against SQL Server, because SQLite serialises writers anyway and would hide the problem.

A page proposal gets its number only when it is approved. A rejected proposal never uses one up.

Numbers are never reused

Archived, closed and permanently deleted items keep their registry entry; a deleted one gets the kind deleted. An old #N in a commit message or a task description therefore never resolves to a newer item.

Numbers from before the shared sequence

Tasks and memories were once numbered separately. The migration to one sequence kept every task number, kept memory numbers that did not collide and moved colliding memories to free numbers above the previous maximum. The old memory number is kept as LegacyNumber, and an old link /projects/<project>/memories/<old-number> still opens that memory. Markdown written before the migration is not rewritten: an old #1 could have meant either kind.

Addresses for pages

In the web app a page lives at /projects/{project}/docs/{number}/{path}, where the path is made of the slugs of its ancestors and its own title. Renames and moves change the path, never the number, and outdated paths redirect. See Web routes (#289).

Sep 17, 2026Claude Code

Item numbering

Tasks, memories and documentation pages take their numbers from one sequence per project. #48 therefore names exactly one item, and item_get(projectId, number) returns it together with its kind. No typed reader has to be chosen first.

A bare #N only means something together with a project. Unknown and inaccessible numbers return the same message, so a caller learns neither the kind nor the title of an item it may not read.

Qualified references

Form Example Use
Bare #48 Inside one project, e.g. in task descriptions
Project project:<project-id>#48 Across projects and in exports
Typed task:project:<project-id>#48 Diagnostics
Non-project memory user:memory:<id> Personal, organization and system memories

The project form uses the project id, not its slug, so renaming a project breaks no reference. Personal, organization and system memories stay outside the sequence and are never inferred from a bare number. Project instructions have no number; tools address them with ref=instructions.

Allocation

ProjectItemService reserves the next number inside the writing transaction, under a lock on the project row (Projects.NextItemNumber), and registers the item in ProjectItems. The registry key (ProjectId, Number) enforces uniqueness across kinds. ItemNumberConcurrencyTests checks this against SQL Server, because SQLite serialises writers anyway and would hide the problem.

A page proposal gets its number only when it is approved. A rejected proposal never uses one up.

Numbers are never reused

Archived, closed and permanently deleted items keep their registry entry; a deleted one gets the kind deleted. An old #N in a commit message or a task description therefore never resolves to a newer item.

Numbers from before the shared sequence

Tasks and memories were once numbered separately. The migration to one sequence kept every task number, kept memory numbers that did not collide and moved colliding memories to free numbers above the previous maximum. The old memory number is kept as LegacyNumber, and an old link /projects/<project>/memories/<old-number> still opens that memory. Markdown written before the migration is not rewritten: an old #1 could have meant either kind.

Addresses for pages

In the web app a page lives at /projects/{project}/docs/{number}/{path}, where the path is made of the slugs of its ancestors and its own title. Renames and moves change the path, never the number, and outdated paths redirect. See Web routes (#289).

Sep 16, 2026Claude Code

Item numbering

Tasks, memories and documentation pages take their numbers from one sequence per project. #48 therefore names exactly one item, and item_get(projectId, number) returns it together with its kind.

Allocation

ProjectItemService reserves the next number inside the writing transaction, under a lock on the project row (Projects.NextItemNumber). Two agents writing at the same moment never receive the same number. ItemNumberConcurrencyTests checks this against SQL Server, because SQLite serialises writers anyway and would hide the problem.

A page proposal gets its number only when it is approved. A rejected proposal never uses one up.

What stays outside the sequence

Personal, organization and system memories belong to no project and are addressed by their own reference. Project instructions have no number either; tools address them with ref=instructions.

Numbers are never reused

A permanently deleted item keeps its entry in ProjectItems with the kind deleted. An old #N in a commit message or a task description therefore never resolves to a newer item. It resolves to nothing, and never reveals the old title.

Addresses for pages

In the web app a page lives at /projects/{project}/docs/{number}/{slug}. The slug is derived from the current title, so a rename changes it while the number stays. Links with an outdated slug, a bare number or only a slug redirect to the current address. A slug alone is ambiguous when two pages share a title; the number is what identifies a page.

To remove text that must not be kept, publish a corrected version first, then delete the older ones.

Connection interrupted or session ended. Reload

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.