Context
Operator design steer (2026-06-15), surfaced while resolving the "create a grid via NL tools only" challenge. The agent-facing creation primitive today is component-only and indirect: there is no create_component MCP tool in the agent projection; creation goes through call_method(parentId,'add',[config]) (the ln op = ComponentService.createComponent), which can only create a component parented to a container. An agent cannot create a standalone non-component instance — a Neo.data.Store, a Neo.data.Model, a Neo.controller.* — through Neural Link.
Operator: "create_component => maybe create_instance as a replacement is superior. e.g. create a new store."
Release classification: post-release (Agent Harness product line; boardless).
The Problem
create_component (and its ln / call_method(add) implementation) conflates two concerns: instantiation and parenting-into-a-container. Container-add is the only creation route, so:
- A standalone
Store (no parent container) can't be created via NL — yet stores are first-class possession targets (inspect_store, list_stores, get_record already read them).
- A
Model, Controller, StateProvider, or any non-Neo.component.Base instance is uncreatable.
- The "create a grid" proof had to route through a container
add; it works for components but does not generalize.
A general create_instance — instantiate any Neo class by className/ntype + config, return its id, optionally attach it — is the superior primitive. Component-in-container creation becomes a special case (instantiate + add to a parent); standalone instances (Store/Model/Controller) become possible.
The Architectural Reality
ai/services/neural-link/ComponentService.mjs — createComponent({parentId, config}) → ConnectionService.call(sessionId,'call_method',{id:parentId, method:'add', args:[config], undoKind:'ln'}). Component+parent only.
ai/mcp/server/neural-link/toolService.mjs — ln: ComponentService.createComponent (operationId ln); write-tier, not in the read-only agent projection.
- Neo instantiation primitive:
Neo.create(className|ntype, config) (App-Worker side) returns a live instance with an id — the natural backing call.
- Undo integration: NL mutations carry
undoKind (#9848 transaction/undo stack; #13221/#13286/#13306 undo/redo slices) — create_instance must register an undo entry (destroy the created instance).
- WriteGuard / authz: creation is a write op — must respect the NL write-guard/permission tier (#9559).
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
create_instance NL MCP tool (new) |
operator design steer (2026-06-15) + ADR 0020 possession premise |
Instantiate any Neo class by className or ntype + config (App-Worker Neo.create); return {id, className}. Optional parentId → also add() it to that container (subsumes create_component). |
Reject class-ref (module) args (can't cross the wire — the existing ln constraint); reject unknown className/ntype via the existing NL error path; no parentId → standalone instance (no attach) |
New openapi.yaml operation + skill/reference doc |
Whitebox agent-MCP-surface e2e: standalone Neo.data.Store verified via inspect_store/get_record; grid-container with parentId verified via get_instance_properties/get_component_tree |
create_component / ln (existing) |
this ticket |
Decide: deprecate in favor of create_instance(parentId=…), or retain as a thin convenience alias |
If retained, document as sugar over create_instance |
openapi.yaml ln op description |
The ln op still resolves or is redirected |
| Undo registration |
#9848 + #13221 |
create_instance registers an undo entry that destroys the created instance |
If undo is unsupported for standalone instances, declare it explicitly |
undo-stack docs |
undo e2e: created instance reverts |
(Surface-Anchor V-B-A: ComponentService.createComponent, the ln op, Neo.create, inspect_store/get_record, undoKind all verified live this session against the running NL server + openapi/source; create_instance is explicitly new — no existing surface asserted.)
Decision Record impact
aligned-with ADR 0020 (Neural Link as the runtime possession/mutation surface). No amendment expected; this generalizes the creation primitive within the ADR's premise. If create_instance replaces create_component, that tool-surface decision is recorded in this ticket's resolution.
Acceptance Criteria
Out of Scope
- Arbitrary JS evaluation (rejected — the #13362 "arbitrary code execution" trap; this is constrained instantiation by class + config).
- The
inspect_store schema bug (separate friction ticket).
- Multi-writer / topological locking beyond a single writer.
- Persisting created instances (Memory Core / Git write-through).
Avoided Traps / Gold Standards Rejected
- Arbitrary code execution /
eval-style creation: rejected — constrained to Neo.create(className|ntype, config), no generated JS.
- Keeping creation container-only: the trap this ticket fixes — it blocks standalone Store/Model/Controller creation.
- Passing a class reference (
module) over the wire: rejected — can't serialize; className/ntype only.
Related
- Operator design steer; surfaced by the live NL-tools grid-creation proof (PR #13363 / #13362).
- Generalizes:
create_component / ln (ComponentService.createComponent).
- Deps: #9848 (transaction/undo stack), #13221/#13286/#13306 (undo/redo slices), #9559 (NL authz). ADR 0020.
- Agent Harness epic: #13012.
Origin Session ID
0f5d9f1d-0683-452d-aac1-f467297186ac
Handoff Retrieval Hints
query_raw_memories: "create_instance Neural Link general instance creation standalone store supersede create_component"; exact anchors: ComponentService.createComponent → call_method(add); Neo.create.
Live latest-open sweep: checked latest 20 open issues 2026-06-15 (this session); no existing create_instance / general-NL-creation ticket (NL tickets #13221/#13286/#13306 are undo/redo; #9848 transaction stack; #9821 VDOM sync) — net-new.
Context
Operator design steer (2026-06-15), surfaced while resolving the "create a grid via NL tools only" challenge. The agent-facing creation primitive today is component-only and indirect: there is no
create_componentMCP tool in the agent projection; creation goes throughcall_method(parentId,'add',[config])(thelnop =ComponentService.createComponent), which can only create a component parented to a container. An agent cannot create a standalone non-component instance — aNeo.data.Store, aNeo.data.Model, aNeo.controller.*— through Neural Link.Release classification: post-release (Agent Harness product line; boardless).
The Problem
create_component(and itsln/call_method(add)implementation) conflates two concerns: instantiation and parenting-into-a-container. Container-addis the only creation route, so:Store(no parent container) can't be created via NL — yet stores are first-class possession targets (inspect_store,list_stores,get_recordalready read them).Model,Controller,StateProvider, or any non-Neo.component.Baseinstance is uncreatable.add; it works for components but does not generalize.A general
create_instance— instantiate any Neo class byclassName/ntype+ config, return its id, optionally attach it — is the superior primitive. Component-in-container creation becomes a special case (instantiate +addto a parent); standalone instances (Store/Model/Controller) become possible.The Architectural Reality
ai/services/neural-link/ComponentService.mjs—createComponent({parentId, config})→ConnectionService.call(sessionId,'call_method',{id:parentId, method:'add', args:[config], undoKind:'ln'}). Component+parent only.ai/mcp/server/neural-link/toolService.mjs—ln: ComponentService.createComponent(operationIdln); write-tier, not in the read-only agent projection.Neo.create(className|ntype, config)(App-Worker side) returns a live instance with an id — the natural backing call.undoKind(#9848 transaction/undo stack; #13221/#13286/#13306 undo/redo slices) —create_instancemust register an undo entry (destroy the created instance).Contract Ledger Matrix
create_instanceNL MCP tool (new)classNameorntype+ config (App-WorkerNeo.create); return{id, className}. OptionalparentId→ alsoadd()it to that container (subsumescreate_component).module) args (can't cross the wire — the existinglnconstraint); reject unknownclassName/ntypevia the existing NL error path; noparentId→ standalone instance (no attach)Neo.data.Storeverified viainspect_store/get_record;grid-containerwithparentIdverified viaget_instance_properties/get_component_treecreate_component/ln(existing)create_instance(parentId=…), or retain as a thin convenience aliascreate_instancelnop descriptionlnop still resolves or is redirectedcreate_instanceregisters an undo entry that destroys the created instance(Surface-Anchor V-B-A:
ComponentService.createComponent, thelnop,Neo.create,inspect_store/get_record,undoKindall verified live this session against the running NL server + openapi/source;create_instanceis explicitly new — no existing surface asserted.)Decision Record impact
aligned-with ADR 0020(Neural Link as the runtime possession/mutation surface). No amendment expected; this generalizes the creation primitive within the ADR's premise. Ifcreate_instancereplacescreate_component, that tool-surface decision is recorded in this ticket's resolution.Acceptance Criteria
create_instanceNL tool instantiates a Neo class byclassName/ntype+ config and returns its live id.Neo.data.Store(noparentId), verifiable viainspect_store/get_record.parentId, it creates + attaches a component to a live container (subsumescreate_component/ln), verifiable viaget_component_tree.module) args and unknownclassName/ntypevia the existing NL error path.create_component/lnrecorded (deprecate vs retain-as-alias).Out of Scope
inspect_storeschema bug (separate friction ticket).Avoided Traps / Gold Standards Rejected
eval-style creation: rejected — constrained toNeo.create(className|ntype, config), no generated JS.module) over the wire: rejected — can't serialize;className/ntypeonly.Related
create_component/ln(ComponentService.createComponent).Origin Session ID
0f5d9f1d-0683-452d-aac1-f467297186ac
Handoff Retrieval Hints
query_raw_memories: "create_instance Neural Link general instance creation standalone store supersede create_component"; exact anchors:ComponentService.createComponent→call_method(add);Neo.create.Live latest-open sweep: checked latest 20 open issues 2026-06-15 (this session); no existing create_instance / general-NL-creation ticket (NL tickets #13221/#13286/#13306 are undo/redo; #9848 transaction stack; #9821 VDOM sync) — net-new.