Skip to content

viant/forge

Repository files navigation

Forge

Forge is an open-source framework for building modern web applications.
It features a React-based frontend and a Go backend, offering flexibility and scalability for dynamic, interactive applications. Forge has been built with LLMs, leveraging AI-powered capabilities to enhance development and functionality.

Table of Contents

Documentation

Introduction

Forge aims to simplify the development of web applications by providing a structured approach that integrates both frontend and backend development. With reusable components and services, developers can focus on building features rather than setting up configurations.

Features

  • Modular React Components: Reusable components such as LayoutRenderer, Container, FileBrowser, and Editor for building dynamic user interfaces.
  • State Management with Signals: Utilizes @preact/signals-react for efficient state management and reactivity.
  • Window and Dialog Management: Handle multiple windows and dialogs within the application using WindowManager and ViewDialog.
  • Data Handling and Services: Backend services in Go for handling data operations, including file browsing, navigation, and metadata loading.
  • Dynamic Form and Table Rendering: Render forms and tables dynamically based on configurations.
  • Chart Integration: Supports data visualization with chart components.
  • File System Integration: Access and manipulate files using the backend file service.

Architecture

Forge is divided into two main parts:

  • Frontend: Built with React and utilizes modern JavaScript features along with libraries like Blueprint.js for UI components.
  • Backend: Built with Go (Golang), providing APIs and services to the frontend. It uses the viant/afs library for abstract file system interactions.

Multi-Platform Metadata

Forge should be treated as the canonical owner of the target-aware metadata contract used by its generic metadata-driven UI/runtime. Forge is not an agentic dependency; applications such as Agently can reuse the same target shape outside Forge when they need consistent client identity elsewhere.

Shared target context

Use one shared target-context shape across:

  • metadata/window requests
  • runtime metadata resolution
  • any application-level context that intentionally chooses to mirror the same client identity contract

Recommended shape:

{
  "platform": "web|android|ios",
  "formFactor": "desktop|tablet|phone",
  "surface": "browser|app",
  "capabilities": ["markdown", "chart", "upload", "code", "diff"]
}

Rules:

  • do not create different shapes for metadata calls vs any app-level reuse of the same client identity contract
  • Forge owns the field names and matching semantics
  • apps and SDKs should reuse the same structure

Current vocabulary in use:

  • markdown: rich markdown rendering
  • chart: chart/data visualization rendering
  • upload: browser file upload support
  • code: code-oriented rendering/edit affordances on web
  • diff: diff rendering on web
  • attachments: attachment-aware mobile composer/runtime support
  • camera: camera capture support on mobile
  • voice: voice input/capture support on mobile

These are additive platform capabilities, not a replacement for the primary branching axes of platform and formFactor.

Metadata branching

Platform-specific UI should use explicit metadata branches instead of deleting or overriding shared web windows.

Recommended structure:

metadata/window/<window-key>/
  shared/
  web/
  android/
    phone/
    tablet/
  ios/
    phone/
    tablet/

Resolution order:

  1. exact platform + form factor
  2. platform
  3. shared
  4. legacy fallback during migration only

Backend responsibility

Forge backend window loading should resolve the target branch before loading main.yaml.

Forge backend $import(...) should also become target-aware so relative imports search in this order:

  1. current target branch
  2. platform branch
  3. shared branch
  4. legacy relative path fallback

Without this, platform folder branches are brittle because target-specific main.yaml files can still import the wrong child metadata.

Installation

Prerequisites

  • Node.js (version 14.x or higher)
  • npm (version 6.x or higher) or Yarn (version 1.x or higher)
  • Go (version 1.16 or higher)
  • Git

Frontend Setup

  1. Clone the Repository

    git clone https://github.com/yourusername/forge.git
  2. Navigate to the Frontend Directory

    cd forge/src
  3. Install Dependencies

    Using npm:

    npm install

    Or using Yarn:

    yarn install
  4. Start the Development Server

    Using npm:

    npm start

    Or using Yarn:

    yarn start

    The application should now be running at http://localhost:3000.

Backend Setup

  1. Navigate to the Backend Directory

    cd forge/backend
  2. Install Go Modules

    go mod download
  3. Run the Backend Server

    go run main.go

    The backend server should now be running, typically at http://localhost:8080.

Usage

Running the Application

With both the frontend and backend servers running, you can access the application in your web browser at http://localhost:3000.

Available Components

  • Window Manager (WindowManager.jsx): Manages multiple windows or views within the application.
  • Container (Container.jsx): Handles layouts and rendering of various UI components.
  • File Browser (FileBrowser.jsx): Allows users to navigate and manage files within the application.
  • Editor (Editor.jsx): Provides a code or text editor with syntax highlighting using CodeMirror.
  • Table Panel (TablePanel.jsx): Displays data in table format with features like sorting, filtering, and pagination.
  • Control Renderer (ControlRenderer.jsx): Dynamically renders form controls based on configuration.
  • Chart (Chart.jsx): Visualizes data using chart components.
  • Layout Renderer (LayoutRenderer.jsx): Builds complex nested page layouts declared in metadata.
  • Splitter (Splitter.jsx): Adds resizable split-pane layouts.

Grid layout (new)

  • Containers can opt into a coordinate-free grid with colspan/rowspan by setting layout.kind: "grid" and layout.columns.
  • Labels default to separate cells on the left; change via layout.labels.mode.
  • See docs/grid-layout.md for usage and examples.
  • Form Renderer (FormRenderer.jsx): Auto-generates forms from JSON-Schema or UI metadata.
  • Tree Multi-Select (TreeMultiSelect.jsx): Hierarchical multi-select control.
  • Avatar Icon (AvatarIcon.jsx): Lightweight Phosphor-icon wrapper used by Chat.
  • Dialog and Modal Components (ViewDialog.jsx): Manages dialogs and modals within the application.
  • Chat (Chat.jsx): High-level chat UI with message feed, composer and dynamic avatar icons (see below).

Dynamic avatar icons in Chat

Chat renders an avatar next to every message. Starting with Forge 1.1 you can fully control which icon is shown.

  1. Per-message override – set iconName on the message object.

    handlers.dataSource.setFormData({
      role: 'assistant',
      iconName: 'Crown',   // <- any icon name from @phosphor-icons/react
      content: 'Welcome back, your Majesty!',
    });
  2. Per-chat mapping – pass a static map or function via the avatarIcons prop:

    <Chat
      avatarIcons={{
        user: 'UserCircle',
        assistant: 'Smiley',
        tool: 'UserGear',
      }}
    />
    
    // or
    const pickIcon = (msg) =>
      msg.role === 'assistant' && msg.metadata?.vip ? 'Crown' : 'Smiley';
    
    <Chat avatarIcons={pickIcon} />
  3. App-wide default – set once during bootstrap:

context.handlers.chat.avatarIcons = { user: 'User', assistant: 'Student' };


4. **YAML screen descriptor** – declare in the container metadata:

 ```yaml
 chat:
   avatarIcons:
     user: UserCircle
     assistant: Student
     tool: SealCheck

 # or dynamic
chat:
  avatarIconsFn: |
    (msg) => msg.role === 'assistant' && msg.meta?.admin ? 'Crown' : 'Smiley'

Icons are provided by the @phosphor-icons/react package. Browse the full catalogue at https://phosphoricons.com/ and use the component name (e.g. SmileyWink, UserGear) as the icon string.

Terminate Button Visibility

Chat includes a circular action button that toggles between Send and Terminate. Visibility of the Terminate state can be controlled declaratively via abortVisible or statically via showAbort.

  • Precedence (highest → lowest):

    • showAbort prop override
    • chat.abortVisible { selector, when } (data-bound)
    • chat.showAbort (static on/off)
    • loading (auto fallback)
  • Data-bound visibility (recommended):

    chat:
      abortVisible:
        selector: "job.status"           # resolved from form data
        when: ["queued", "running"]     # show Terminate while async job is in these states
      # Optional: read from another DataSource
      # abortVisible:
      #   dataSourceRef: otherDS
      #   selector: "job.status"
      #   when: ["queued", "running"]
    • Selector source: the chat’s bound DataSource form (context.signals.form) by default. Use abortVisible.dataSourceRef to read from another DataSource.
    • when semantics:
      • omitted → Terminate shows when the selector value is truthy.
      • scalar → Terminate shows when selector === when.
      • array → Terminate shows when selector is in when.
  • Typical flow:

    • onSubmit handler starts async work and sets form data (e.g., job.status = "running").
    • A poller updates the form when done/failed (e.g., job.status = "done"), which hides Terminate.
    • onAbort handler cancels and flips the form field to a non-matching value (e.g., "aborted").

Backend Services

  • File Service (file/service.go): Provides file system operations like listing directories and downloading files.
  • Metadata Service (meta/service.go): Loads and resolves metadata with support for YAML files and $import directives.
  • Navigation Handler (handlers/navigation.go): Fetches navigation data for building menus or navigation trees.
  • Window Handler (handlers/meta.go): Loads window data and configurations.

Contributing

We welcome contributions from the community. To contribute:

  1. Fork the Repository

    Click the "Fork" button on the repository page to create a copy under your GitHub account.

  2. Create a Branch

    git checkout -b feature/your-feature-name
  3. Make Your Changes

    Edit the code to add new features or fix bugs.

  4. Commit Your Changes

    git commit -am "Add new feature"
  5. Push to Your Fork

    git push origin feature/your-feature-name
  6. Submit a Pull Request

    Go to the original repository and click on "New Pull Request" to submit your changes for review.

Please ensure your code follows the existing code style and includes appropriate comments and documentation.

License

This project is licensed under the Apache2 License. See the LICENSE file for details.

Acknowledgments

  • Library Author: Adrian Witas
  • Viant AFS: For the abstract file system used in the backend services.
  • Blueprint.js: For the UI components used in the frontend.
  • CodeMirror: For providing the editor component with syntax highlighting.

About

data driven ui

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors