Skill v1.0.0
currentTrusted Publisher100/100name: space description: Space mental model (the infinite work surface), tool boundaries, and command reference. The single entry point for any agent operating on a Huabu Space. appliesTo: [ask, operate, external] version: 1
Space
The canonical reference for working with a Huabu Space. This file covers the read side: the on-disk layout and the tools that turn it into structured data. Mutation is gated behind a separate tool (space_commands) and a separate reference file — see the Mutating a Space section below.
Schemas are the source of truth. This skill explains _semantics_ and _idioms_. Field names, types, and required parameters live on the corresponding tool / command schema. When in doubt about a field, trust the schema.
A Space has two surfaces
A Space exposes two complementary surfaces, each owned by its own family of tools. Pick the family by what you want to know, not by which tool feels familiar.
Surface A — A folder of text files
Node text, frontmatter, skill files, memory, history. Read with read, find, ls, grep.
<Space>/nodes/<safeLabel>.md # one file per node: YAML frontmatter + Markdown bodymemory/*.md # long-form, agent-curated memoryskills/<id>/SKILL.md # per-Space skill overrides (optional).artifacts/<id><ext> # raw bytes (image / pdf / video / cover); `read` returns images inline, rejects pdf / video.history/ # saved threads, event log (rarely needed)
A node's filename is deterministically derived from its label and kept in 1:1 sync, so when you have the label you can build the path yourself:
nodes/<safeLabel>.md
safeLabel = the label with characters \ / : * ? " < > | (and ASCII control chars) replaced by _. Spaces, hyphens, parentheses, dots, and any other character are kept verbatim — do not substitute them. Only leading/trailing dots and spaces are stripped, and the result is truncated to 120 chars. Empty / missing labels fall back to the stable nodeId.
Examples:
| label | safeLabel | path | |
|---|---|---|---|
Dolphin Migration | Dolphin Migration | nodes/Dolphin Migration.md | |
Notes (draft) | Notes (draft) | nodes/Notes (draft).md | |
Foo: Bar / Baz | Foo_ Bar _ Baz | nodes/Foo_ Bar _ Baz.md | |
trailing. | trailing | nodes/trailing.md |
- Have the label →
read("nodes/<safeLabel>.md")directly. Don'tfindfirst when you already have the label — build the path. - Have only the nodeId →
find("nodes/*.md")orgrep(results carrynodeId,label,nodeType); the stable id also lives in each file'sid:frontmatter. - A direct read returns ENOENT (rare — usually means the label was just edited mid-flight) → fall back to
find/grep.
Surface B — Layout & connectivity data (space.json)
Where each node sits, how big it is, which frame it belongs to, what colour it's painted; every edge's endpoints and style. Stored as one space.json per Space, served through get_space_outline, inspect_nodes, inspect_edges. These tools also expose derived fields you can't read off disk — distance, direction, hops, clusterId, arrangement — computed on the fly from the same data, which is why you should query through them rather than read("space.json") and parse it yourself.
Boundary rule of thumb
| Property | Tool | |
|---|---|---|
| label, content, summary, keywords, src | read / grep | |
| position, size, parentFrame, visual style | inspect_nodes | |
| edge direction / lineStyle / stroke | inspect_edges | |
| whole-Space overview, spatial clusters | get_space_outline |
Tool decision matrix
| Question | Tool | |
|---|---|---|
| "Give me the lay of the land" | get_space_outline() | |
| "What does this node say?" | read("nodes/<safeLabel>.md") | |
| "Where is this node? How big? In which frame?" | inspect_nodes({ ids: ["<id>"] }) | |
| "What's near this node?" | inspect_nodes({ nearNode: { id } }) | |
| "What connects to this node?" | inspect_nodes({ connectedTo: { id } }) | |
| "What does that edge look like?" | inspect_edges({ ids: ["<edgeId>"] }) | |
| "Which nodes mention 'gradient descent'?" | grep | |
| "List all PDFs" | find("**/*.pdf") or inspect_nodes({ byType: "pdf" }) | |
| "Load a deeper Space reference" | read("skills/space/references/<name>.md") |
Gotchas
Behaviour the schema can't convey:
- Selection & Position Geometry (CRITICAL): The selected-node / anchor context DOES NOT directly contain position, size, parent frame, or geometry coordinates. If you need to place a new node near, relative to, or offset from a selected or anchor node, you MUST first call `inspect_nodes({ ids: ["<anchorId>"] })` (or
get_space_outline) to query its geometry. - Coordinates — idioms. Each node carries two coordinate fields (defined on the
inspect_nodes/space_commandsschemas): writable parent-localpositionand read-only worldabsolutePosition. Practical placement: to put a child next to a sibling in the same frame, add an offset to the sibling'sposition; to place a root node near some reference, use the reference'sabsolutePosition(root-local == world); to align a framed child to something outside its frame, submittarget.absolutePosition − thisFrame.absolutePosition. Into acolumn/row/grid(structured) frame,positionis only a sort hint — the frame owns the final slot. Ingridmodepositiondoes not decide rows either: passcellsonSET_FRAME_LAYOUTto place children, giving paired children the samerow. - Nodes in context are metadata only. Pass a node's supplied
filepath straight toreadfor the body. Only when a node is mentioned outside your context (e.g. it appears in a Space snapshot but wasn't shown as a<node>) do you build the path yourself via the safeLabel rule above. For spatial / structural info (including position), callinspect_nodes({ ids: ["<id>"] }). - Cross-Space reads are World-only. Tools default to the conversation's Space. In a World conversation, first read the World outline, take
targetCanvasIdfrom a canonicalspacePreview, then pass it toget_space_outline,inspect_nodes,inspect_edges,read,grep,find, orls. The target must be a live ordinary Space addressed by exactly one canonical preview.snapshot_nodesremains owner-scoped because it materializes cache artifacts; usereadwithtargetCanvasIdto view source images inline. This never grants cross-Space writes;space_commandsremains World-scoped. - `read` returns image artifacts inline as vision content: pass an image node's frontmatter
srcstraight toread, OR — for an inlineimage embedded in a note body — callread(".artifacts/<key>")to see it. PDF / video bytes still live under.artifacts/but are not readable — theirsrcURL is the only handle. - Before placing new nodes, anchor on the selection / a referenced node / a focal cluster — never pick coordinates from the global bbox alone, or new nodes land outside the user's viewport. If setting
size, inspect and match comparable nearby nodes; with no comparable peer, omit it and use the canonical default. Seelayout-recipes.mdfor long-Note and per-type sizing rules.
Mutating a Space
The filesystem tools (read, find, ls, grep) are read-only — there is no write / edit_file / rm. Every mutation flows through one tool: `space_commands`.
- If
space_commandsis not in your available tool list → you are in read-only mode. Do not attempt mutations and do not claim in your reply that you performed any. - If
space_commandsis available → the tool's own schema and description carry the full command set, the id / dependency-ordering rule, and per-field behaviour. For composed multi-command recipes seecommand-cookbook.md; for diagram geometry seelayout-recipes.md. - Commands are not guaranteed to succeed. Each command in a call reports its own outcome in
results[]; on failure it carries areason(e.g.invalid-targetwhen a CONNECT / SET_NODE_PARENT endpoint doesn't exist). Read it and adjust — don't assume a write landed.
Deeper dives
Load on demand when the situation calls for it:
read("skills/space/references/command-cookbook.md")— composed batch patterns: brainstorm, merge / synthesize, group into a frame, restyle a cluster, tidy a row, …read("skills/space/references/layout-recipes.md")— coordinate system, hierarchical / left-to-right / grid layouts, frames (including when to pick the row-alignedgridframe mode overcolumn), and the row-track flowchart / roadmap recipe.