The shape an editor client takes when it discovers, parameterizes, executes, and places the output of an Oculus code fence. The Doom Emacs (+wanderland.el) and Neovim (wanderland.lua) integrations realize this contract; Lantern (web) is the expected third.
A fence execution passes through five stages:
Each stage is independent. A client can swap the front end (selector, prompt style) or the tail (destinations) without touching the middle.
Three selection primitives, each yielding a single fence id:
| Selector | Scope | Source |
|---|---|---|
| point | the fence surrounding the cursor | local buffer scan, parse the fence info line |
| node | one fence from the current node | GET /api/oculus/fences?slug={slug} |
| graph | one fence from the registry | GET /api/oculus/fences |
The point selector parses either an auto-injected [id=…] or a hand-written [label] in the opening fence info line. The node and graph selectors present a completion UI over the fence list and return the chosen fence's id.
[id=…] is auto-injected into fence info lines when a node is rendered. Raw buffers carry only labels the author wrote themselves.
The point selector therefore requires a rendered buffer (or a labeled fence in a raw buffer). When point is invoked on a raw buffer, the client offers three paths:
Unlabeled fences in raw buffers cannot be addressed at point — the guidance is to add a [label] to the info line.
GET /api/oculus/fences/{id}/params
Returns:
{
"fence_id": "…",
"fence_label": "…",
"slug": "…",
"params": [
{
"name": "…",
"type": "string",
"description": "…",
"default": null,
"optional": false,
"from": "docstring"
}
],
"required": ["…"],
"optional": [],
"example_call": { "fence_id": "…", "params": {} }
}
Required params are prompted one at a time. Optional params are prompted with a skip affordance (or omitted entirely; both implementations allow empty-input skipping).
POST /api/oculus/fences/{id}/execute
Content-Type: application/json
{ "params": { "key": "value", ... } }
Response:
{
"success": true,
"fence_id": "…",
"fence_type": "python",
"slug": "…",
"data": "<string | object>",
"formatted": "<string | object>",
"format": "markdown | json | yaml | text",
"metadata": { "type": "python", "provider": "python_exec", "has_output": true },
"error": null
}
Clients format output using formatted when present, falling back to data. The format field picks the display mode (markdown, json, yaml, text). A non-null error is shown as-is and short-circuits dispatch formatting.
Five output targets. A client offers any subset. replace-body requires the fence body bounds and is typically only offered by the point selector.
| Destination | Effect |
|---|---|
| buffer | new split / window / virtual buffer with the formatted result, filetype from format |
| point | insert the formatted result at the cursor in the source buffer |
| replace-body | swap the text between the fence markers with the result; markers remain, so the fence stays re-executable |
| kill-ring | copy to the system clipboard or yank register |
| message | show in the minibuffer / notification area |
replace-body needs the line range of the fence body. From the opening info line at line L:
^+\s*$`)[L + 1, close_line - 1], 1-indexed inclusiveAn empty fence produces start > end, which collapses to an insert at line L + 1.
The complete set of endpoints a fence execution client uses:
| Method | Path | Purpose |
|---|---|---|
GET |
/api/oculus/fences |
registry — all fences |
GET |
/api/oculus/fences?slug={slug} |
one node — its fences |
GET |
/api/oculus/fences/{id}/params |
parameter schema |
POST |
/api/oculus/fences/{id}/execute |
run the fence |
| Stage | Emacs (+wanderland.el) |
Neovim (wanderland.lua) |
|---|---|---|
| point | wanderland--fence-at-point-bounds |
M.oculus_fence_at_cursor + M._fence_body_bounds |
| node | wanderland-fence-on-node |
M.oculus_browse_node_fences |
| graph | wanderland-fence-exec |
M.oculus_browse_fences |
| params fetch | wanderland--fence-get-params |
M.oculus_get_fence_params |
| params prompt | wanderland--fence-prompt-params |
inline prompt_next |
| execute | wanderland--fence-execute |
M.oculus_execute_fence |
| result format | wanderland--fence-format-result |
M._fence_format_result |
| dispatch menu | wanderland--fence-dispatch |
M._fence_dispatch |
Entry points:
| Operation | Emacs | Neovim |
|---|---|---|
| at point | wanderland-fence-at-point (SPC W F .) |
M.oculus_execute_fence_at_cursor (SPC W o x x) |
| on node | wanderland-fence-on-node (SPC W F n) |
M.oculus_browse_node_fences (SPC W o x f) |
| graph | wanderland-fence-exec (SPC W F e) |
M.oculus_browse_fences (SPC W o f) |
An open slot. A web client realizes the contract with equivalent surfaces:
/params schemacmd-fence — the underlying fence system (addressing, labeling, execution semantics)fence-params — the self-documenting fence pattern (how schemas come to exist)emacs-integration — the Emacs realizationneovim-integration — the Neovim realization