Atlas / Skills / wavetermdev / Create View

Create ViewSAFE

skills/wavetermdev/create-view

An open-source, AI-integrated, cross-platform terminal for seamless workflows

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
—
Hosts
—
License
Apache-2.0
Stars
22,404
01

Overview

An open-source, AI-integrated, cross-platform terminal for seamless workflows

Read from source at commit 63907843412fOBSERVED · 2026-10-03
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: create-view
description: Guide for implementing a new view type in Wave Terminal. Use when creating a new view component, implementing the ViewModel interface, registering a new view type in BlockRegistry, or adding a new content type to display within blocks.
---

# Creating a New View in Wave Terminal

This guide explains how to implement a new view type in Wave Terminal. Views are the core content components displayed within blocks in the terminal interface.

## Architecture Overview

Wave Terminal uses a **Model-View architecture** where:

- **ViewModel** - Contains all state, logic, and UI configuration as Jotai atoms
- **ViewComponent** - Pure React component that renders the UI using the model
- **BlockFrame** - Wraps views with a header, connection management, and standard controls

The separation between model and component ensures:

- Models can update state without React hooks
- Components remain pure and testable
- State is centralized in Jotai atoms for easy access

## ViewModel Interface

Every view must implement the `ViewModel` interface defined in `frontend/types/custom.d.ts`:

```typescript
interface ViewModel {
  // Required: The type identifier for this view (e.g., "term", "web", "preview")
  viewType: string;

  // Required: The React component that renders this view
  viewComponent: ViewComponent<ViewModel>;

  // Optional: Icon shown in block header (FontAwesome icon name or IconButtonDecl)
  viewIcon?: jotai.Atom<string | IconButtonDecl>;

  // Optional: Display name shown in block header (e.g., "Terminal", "Web", "Preview")
  viewName?: jotai.Atom<string>;

  // Optional: Additional header elements (text, buttons, inputs) shown after the name
  viewText?: jotai.Atom<string | HeaderElem[]>;

  // Optional: Icon button shown before the view name in header
  preIconButton?: jotai.Atom<IconButtonDecl>;

  // Optional: Icon buttons shown at the end of the header (before settings/close)
  endIconButtons?: jotai.Atom<IconButtonDecl[]>;

  // Optional: Custom background styling for the block
  blockBg?: jotai.Atom<MetaType>;

  // Optional: If true, completely hides the block header
  noHeader?: jotai.Atom<boolean>;

  // Optional: If true, shows connection picker in header for remote connections
  manageConnection?: jotai.Atom<boolean>;

  // Optional: If true, filters out 'nowsh' connections from connection picker
  filterOutNowsh?: jotai.Atom<boolean>;

  // Optional: If true, removes default padding from content area
  noPadding?: jotai.Atom<boolean>;

  // Optional: Atoms for managing in-block search functionality
  searchAtoms?: SearchAtoms;

  // Optional: Returns whether this is a basic terminal (for multi-input feature)
  isBasicTerm?: (getFn: jotai.Getter) => boolean;

  // Optional: Returns context menu items for the settings dropdown
  getSettingsMenuItems?: () => ContextMenuItem[];

  // Optional: Focuses the view when called, returns true if successful
  giveFocus?: () => boolean;

  // Optional: Handles keyboard events, returns true if handled
  keyDownHandler?: (e: WaveKeyboardEvent) => boolean;

  // Optional: Cleanup when block is closed
  dispose?: () => void;
}
```

### Key Concepts

**Atoms**: All UI-related properties must be Jotai atoms. This enables:

- Reactive updates when state changes
- Access from anywhere via `globalStore.get()`/`globalStore.set()`
- Derived atoms that compute values from other atoms

**ViewComponent**: The React component receives these props:

```typescript
type ViewComponentProps<T extends ViewModel> = {
  blockId: string; // Unique ID for this block
  blockRef: React.RefObject<HTMLDivElement>; // Ref to block container
  contentRef: React.RefObject<HTMLDivElement>; // Ref to content area
  model: T; // Your ViewModel instance
};
```

## Step-by-Step Guide

### 1. Create the View Model Class

Create a new file for your view model (e.g., `frontend/app/view/myview/myview-model.ts`):

```typescript
import { BlockNodeModel } from "@/app/block/blocktypes";
import { globalStore } from "@/app/store/jotaiStore";
import { WOS, useBlockAtom } from "@/store/global";
import * as jotai from "jotai";
import { MyView } from "./myview";

export class MyViewModel implements ViewModel {
  viewType: string;
  blockId: string;
  nodeModel: BlockNodeModel;
  blockAtom: jotai.Atom<Block>;

  // Define your atoms (simple field initializers)
  viewIcon = jotai.atom<string>("circle");
  viewName = jotai.atom<string>("My View");
  noPadding = jotai.atom<boolean>(true);

  // Derived atom (created in constructor)
  viewText!: jotai.Atom<HeaderElem[]>;

  constructor(blockId: string, nodeModel: BlockNodeModel) {
    this.viewType = "myview";
    this.blockId = blockId;
    this.nodeModel = nodeModel;
    this.blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);

    // Create derived atoms that depend on block data or other atoms
    this.viewText = jotai.atom((get) => {
      const blockData = get(this.blockAtom);
      const rtn: HeaderElem[] = [];

      // Add header buttons/text based on state
      rtn.push({
        elemtype: "iconbutton",
        icon: "refresh",
        title: "Refresh",
        click: () => this.refresh(),
      });

      return rtn;
    });
  }

  get viewComponent(): ViewComponent {
    return MyView;
  }

  refresh() {
    // Update state using globalStore
    // Never use React hooks in model methods
    console.log("refreshing...");
  }

  giveFocus(): boolean {
    // Focus your view component
    return true;
  }

  dispose() {
    // Cleanup resources (unsubscribe from events, etc.)
  }
}
```

### 2. Create the View Component

Create your React component (e.g., `frontend/app/view/myview/myview.tsx`):

```typescript
import { ViewComponentProps } from "@/app/block/blocktypes";
import { MyViewModel } from "./myview-model";
import { useAtomValue } from "jotai";
import "./myview.scss";

export const MyView: React.FC<ViewComponentProps<MyViewModel>> = ({
    blockId,
    model,
    contentRef
}) => {
03

Trust audit

SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (0)

No findings outside the package's declared scope.

Gates applied: no_behavioural_pass.

Audited 2026-10-03 · audit v0.4.1 · source sha 63907843412ffull audit observations/trust-audit/skill/wavetermdev__create-view.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-0363907843412fSAFEB89first audit
05

Questions

What does the Create View skill do?

An open-source, AI-integrated, cross-platform terminal for seamless workflows

Is Create View safe to install?

The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.

What can Create View access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (63907843412f), read on 2026-10-03. The repository is watched, and a new audit runs when it changes — this is the first audit.

Advertisement