On this page
Survey first, then choose detail๏
Prerequisite: opening a Rift. Start at rift.space.frame_viewer.
The host-level multi-frame view can enumerate frames without selecting one.
The frame, conduit, and spell views require a frame name.
Control the amount you read๏
Use list_* to discover names and IDs, a brief description to decide what matters,
then detail or a specific facet for the selected object. For spells, the ladder is
describe_spell_brief, describe_spell, describe_spell_detail, and
describe_spell_payload. Source, binding, identity, resolution, and research reads
let a caller request a particular concern.
The viewer lessons inspect the method surface and show that a fresh Rift can have an empty assigned-frame set. An empty survey is different from a frame-local request that lacks the required target.
Missing is not always absent๏
A visibility-filtered description may omit a section because it does not exist or because this Rift may not see it. Use the missing-section/visible-surface probes to understand that boundary. They report withheld section names without exposing their hidden payload bodies.
On the facade, frame_name selects the frame. On a view already bound to a frame,
an optional frame name can instead be an assertion that it matches. Read the
specific signature rather than treating those two surfaces as interchangeable.
The workflow in code๏
These are the core steps from the saved example. Use its complete linked script for all class definitions and setup.
1def main() -> None:
2 nexus = md.Nexus()
3 system_config = nexus.create_configuration()
4 system_config.with_rift_creation_enabled(True)
5 nexus.activate(system_config)
6
7 rift_config = nexus.create_rift_configuration()
8 rift_config.with_space_type("capability")
9 rift = nexus.create_rift(configuration=rift_config, rift_name="observatory")
10 rift.mark_active()
11
12 viewer = rift.space.frame_viewer
13 assert isinstance(viewer, md.FrameViewer)
14 print("viewer:", viewer.id)
15
16 # THE FACADE'S COMMON READS. A fresh rift has no assigned frames yet,
17 # so these are honest zeros rather than errors - the read surface
18 # works on an empty world.
19 frame_names = viewer.list_frame_names()
20 print("frames visible:", viewer.count_frames(), frame_names)
21 assert isinstance(frame_names, list)
22 assert viewer.count_frames() == len(frame_names)
23
24 # THE VIEWS SPLIT INTO TWO GROUPS, AND THAT SPLIT IS THE LESSON.
25 #
26 # get_view_multiframe() is HOST-SCOPED - it asks about all frames, so
27 # it needs no frame name and works right now.
28 multiframe = viewer.get_view_multiframe()
29 assert isinstance(multiframe, md.ViewMultiFrame)
30 print("view_multiframe:", type(multiframe).__name__, "(host-scoped)")
31
32 # get_view_frame / get_view_conduit / get_view_spell are FRAME-SCOPED.
33 # THERE IS NO DEFAULT FRAME, and since the signature fix that is now
34 # enforced by the signature itself - omitting the name is a TypeError
35 # at the call, not a ValueError from somewhere inside.
36 for accessor in ("get_view_frame", "get_view_conduit", "get_view_spell"):
37 try:
38 getattr(viewer, accessor)()
39 raise AssertionError(f"{accessor} should require a frame name")
40 except TypeError as error:
41 print(f" {accessor:18s} requires a frame name: {error}")
42
43 # This rift is contracted to no frames, so there is no name to pass -
44 # which is the honest state of a freshly opened rift.
45 assert rift.list_assigned_frame_names() == ()
46 print("assigned frames:", rift.list_assigned_frame_names(),
47 "- nothing to scope a frame-local view to yet")
48
49 # The view TYPES are still inspectable without an instance, which is
50 # how the next two lessons map their surfaces.
51 for view_type in (md.ViewFrame, md.ViewConduit, md.ViewSpell,
52 md.ViewMultiFrame):
53 assert isinstance(view_type, type)
54 print("four view types exported:", ", ".join(
55 t.__name__ for t in (md.ViewFrame, md.ViewConduit, md.ViewSpell,
56 md.ViewMultiFrame)))
57
58 # NO CACHED SNAPSHOT. The facade resolves per invocation, so two calls
59 # hand back two view objects rather than one memoized one.
60 assert viewer.get_view_multiframe() is not viewer.get_view_multiframe()
61 print("fresh view per invocation - nothing to go stale")
62
63 # WHAT VIEWS EXIST? Ask, do not assume.
64 available = viewer.describe_available_views()
65 assert isinstance(available, list)
66 print("describe_available_views ->", len(available), "entries")
67
68 # THE AIX SURFACE. The viewer describes its own method surface...
69 surface = viewer.describe_viewer_method_surface()
70 assert isinstance(surface, dict)
71 print("describe_viewer_method_surface ->", len(surface), "keys")
72
73 # ...and onboards an agent in JSON, at runtime, from the object itself.
74 onboarding = viewer.describe_agent_onboarding_json()
75 assert isinstance(onboarding, str)
76 parsed = json.loads(onboarding)
77 print("describe_agent_onboarding_json -> valid JSON,",
78 len(onboarding), "chars")
79 print(" top-level keys:", sorted(parsed)[:6])
80
81 purpose = viewer.describe_viewer_agent_purpose_json()
82 assert isinstance(purpose, str)
83 json.loads(purpose)
84 print("describe_viewer_agent_purpose_json -> valid JSON")
85
86 # clone() hands back an independent facade over the same world.
87 twin = viewer.clone()
88 assert isinstance(twin, md.FrameViewer)
89 assert twin is not viewer
90 assert twin.count_frames() == viewer.count_frames()
91 print("clone: independent object, same reading")
92
93 print()
94 print("a facade with no snapshot - every read is a fresh resolve")
95 print("and the object onboards its own caller instead of assuming docs")
Runnable examples๏
The frame viewer facade โ Advanced 13
The describe ladder โ Advanced 14
What you cannot see โ Advanced 15