Skip to content

Default new node content to "Untitled {Type}" for name-as-content core types (project, skill) #1995

Closed

Description

@malibio

Overview

project and skill are Core hardcoded node types whose content field is the node's name, not body text — their NodeBehavior::validate() requires it to be non-empty. Every frontend node-creation path that could reach these types (sidebar "+New", slash commands) always creates instances with content: '', so creation always fails validation. This does not affect primitive/body-content types (text, header, code-block, task, etc.) — empty content is correct and expected for those; this issue is scoped only to types where content is the identity.

Problem Statement

project and skill are Core hardcoded types whose behaviors require non-empty content:

  • packages/core/src/behaviors/mod.rs:804 — ProjectNodeBehavior: "content (project name)"
  • packages/core/src/behaviors/mod.rs:1909 — SkillNodeBehavior: "Skill name (content) cannot be empty"

Reproduced directly against the daemon:

$ nodespace node create --type skill --content "" --json
Error: ... InvalidArgument, message: "Validation failed: Missing required field: Skill name (content) cannot be empty"

$ nodespace node create --type project --content "" --json
Error: ... InvalidArgument, message: "Validation failed: Missing required field: content (project name)"

Both types have no working creation path as a result:

  • Neither is registered in packages/desktop-app/src/lib/plugins/core-plugins.ts, so there is no /project or /skill slash command (confirmed via git log -S — neither was ever added; this is a gap, not a regression/removal).
  • The only remaining entry point is the sidebar "+New" button (QueryNodeViewer.handleCreateInstance → createSchemaInstance() in packages/desktop-app/src/lib/services/schema-authoring.ts:24-41), which always creates with content: '' and therefore always fails validation for these two types.

The same content-required pattern exists for three more Core behaviors — no working creation path is confirmed broken for these (they either aren't user-creatable yet or have their own dedicated creation UI), but any future generic creation path for them hits the identical wall unless this fix accounts for them too:

  • collection — packages/core/src/behaviors/mod.rs:1655 ("Collection name (content) cannot be empty") — has its own dedicated creation UI already, unaffected in practice
  • agent-guidance — packages/core/src/behaviors/mod.rs:1859 ("Agent-guidance title (content) cannot be empty")
  • tool — packages/core/src/behaviors/mod.rs:2019 ("Tool display name (content) cannot be empty")

Explicitly not in scope: primitive/body-content types (text, header, code-block, quote-block, ordered-list, task, etc.) correctly create with empty content today — that's the expected "start typing" state, not a bug. This issue must not touch their creation defaults.

Proposed Solution

For the specific set of Core types whose NodeBehavior requires non-empty content (project, skill, and — for consistency, since they share the identical constraint — collection, agent-guidance, tool), default content to "Untitled {Display Name}" at the point(s) where the frontend currently hardcodes content: '' for them:

  • createSchemaInstance() (packages/desktop-app/src/lib/services/schema-authoring.ts:24-41) — the sidebar "+New" path; needs to special-case (or look up) this set of types rather than blindly defaulting every type
  • Any future core-plugins.ts slash command entries added for project/skill (out of scope to add here, see Non-Goals, but the content-default mechanism should be reusable if/when they're added)

This must be scoped narrowly — by an explicit list, a shared marker, or a lookup against NodeBehavior — so it never applies to primitive body-content types or to titleTemplate-driven custom entities (see Architecture Impact).

Architecture Impact

../nodespace-docs/components/schema-management.md:302 states: "The content field is always empty ('') — never \"Untitled\". Content is not the name." — this line is scoped specifically to the titleTemplate case (custom schema types whose display title is computed from properties via compute_title(), where content is deliberately kept empty as a hidden field, not shown to the user). It sits directly under the doc's "With titleTemplate" behavior section (lines 299-304).

This issue does not reverse that rule and must not apply its default to titleTemplate types (see Non-Goals). No other ADR or architecture doc describes a content-default convention for name-as-content Core types; this issue establishes that convention for the first time, narrowly scoped to that category. No companion nodespace-docs change is required unless the implementer judges the new convention worth documenting alongside the existing titleTemplate section.

Acceptance Criteria

  • Sidebar "+New" (createSchemaInstance) creates project and skill instances successfully (previously failed with InvalidArgument)
  • project and skill instances created via "+New" default to non-empty, type-identifying content (e.g. "Untitled Project" / "Untitled Skill" — exact wording is an implementation choice)
  • Primitive/body-content types (text, header, code-block, task, etc.) are unaffected — verify they still create with empty content, not "Untitled"
  • Custom schema types with a titleTemplate are unaffected — their content remains '' per schema-management.md:302
  • Regression test: creating a project/skill instance via the sidebar "+New" flow (or the equivalent service-level call) succeeds and round-trips a non-empty content value
  • Regression test: creating a primitive type (e.g. text or task) via the same code path still results in empty content
  • No new test failures (bun run test:all)
  • Code passes bun run quality:fix

Technical Specifications

Reference Files

  • packages/desktop-app/src/lib/services/schema-authoring.ts (lines 24-41) — createSchemaInstance(), the sidebar "+New" creation call; currently hardcodes content: '' for every type
  • packages/desktop-app/src/lib/components/viewers/query-node-viewer.svelte (line 510-546) — handleCreateInstance(), calls createSchemaInstance() and surfaces createError from a failed create; useful to confirm the error disappears once the fix lands
  • packages/core/src/behaviors/mod.rs — validation source of truth: ProjectNodeBehavior::validate (~line 804), SkillNodeBehavior::validate (~line 1909), CollectionNodeBehavior::validate (~line 1655), AgentGuidanceNodeBehavior::validate (~line 1859), ToolNodeBehavior::validate (~line 2019), vs. CustomNodeBehavior::validate (line 2199-2209, explicitly permits empty content) and primitive-type behaviors (no content check)

Implementation Notes

  • A display name for the "Untitled {Type}" string can be sourced the same way createPluginFromSchema() derives one: schema.content || humanizeSchemaId(schemaId) (packages/desktop-app/src/lib/plugins/schema-plugin-loader.ts:118).
  • Do not touch backend validation (CustomNodeBehavior::validate() or any NodeBehavior impl) — this is purely a frontend default-content fix. The backend behaviors correctly enforce their own rules; the bug is that the frontend never supplies a value that satisfies them for this specific subset of types.
  • Prefer an explicit, named list (or a small lookup table) of "name-as-content" types over inferring it from schema shape — there is no existing frontend signal (schema field, isCore flag, etc.) that distinguishes project/skill from task/text; encoding it implicitly (e.g. "core types with no schema fields") would be fragile and likely to silently drift as new Core types are added.

Non-Goals

  • Does not implement ai-chat's "Untitled" default or its async LLM title-generation — that is Auto-generate ai-chat conversation titles via idle-gated background LLM task #1698's scope in full.
  • Does not change titleTemplate custom-entity behavior — content stays '' for those, per schema-management.md:302.
  • Does not change any primitive/body-content type's creation default (text, header, code-block, task, etc.) — empty content is correct for these.
  • Does not add a /project or /skill slash command — this issue only fixes the existing "+New" creation path. Adding those slash commands (if desired) is separate, additive scope.

Related Issues

Activity

  1. changed the title [-]Default new node content to "Untitled" for types with no template-driven title[/-] [+]Default new node content to "Untitled {Type}" for name-as-content core types (project, skill)[/+] on Aug 7, 2026
  2. mstomar125 commented on Aug 10, 2026

    @mstomar125
    Contributor

    Resolved by PR #2018 (merged, main c4218cec). createSchemaInstance now seeds "Untitled {Type}" for the name-as-content Core types (project, skill, collection, agent-guidance, tool), so the sidebar "+New" path succeeds for them instead of failing non-empty-content validation; body-content and titleTemplate/custom types keep empty content. Verified against the actual behavior.type_name() keys; +2 unit tests; independent review APPROVE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingui

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions