go/docs/services/workspace.md

3.1 KiB

Workspace Service

The Workspace service (pkg/workspace) manages isolated user workspaces with encrypted storage and PGP key pairs.

Features

  • Isolated workspace environments
  • PGP key pair generation per workspace
  • Encrypted workspace identification
  • File operations within workspace context
  • Multiple workspace support

Basic Usage

import "github.com/Snider/Core/pkg/workspace"

// With IO medium (standalone)
medium, _ := local.New("/app/workspaces")
ws, err := workspace.New(medium)

// With Core framework (recommended)
c, _ := core.New(
    core.WithService(workspace.Register),
)
ws := core.MustServiceFor[*workspace.Service](c, "workspace")

Creating Workspaces

// Create a new encrypted workspace
workspaceID, err := ws.CreateWorkspace("my-project", "secure-password")
// Returns obfuscated workspace ID

// Workspace structure created:
// workspaces/
//   <workspace-id>/
//     config/
//     log/
//     data/
//     files/
//     keys/
//       key.pub   (PGP public key)
//       key.priv  (PGP private key)

Switching Workspaces

// Switch to a workspace
err := ws.SwitchWorkspace(workspaceID)

// Switch to default workspace
err := ws.SwitchWorkspace("default")

Workspace File Operations

// Write file to active workspace
err := ws.WorkspaceFileSet("config/settings.json", jsonData)

// Read file from active workspace
content, err := ws.WorkspaceFileGet("config/settings.json")

Listing Workspaces

// Get all workspace IDs
workspaces := ws.ListWorkspaces()
for _, id := range workspaces {
    fmt.Println(id)
}

Active Workspace

// Get current workspace info
active := ws.ActiveWorkspace()
if active != nil {
    fmt.Println("Name:", active.Name)
    fmt.Println("Path:", active.Path)
}

Workspace Structure

Each workspace contains:

Directory Purpose
config/ Workspace configuration files
log/ Workspace logs
data/ Application data
files/ User files
keys/ PGP key pair

Security Model

Workspaces use a two-level hashing scheme:

  1. Real Name: Hash of the identifier
  2. Workspace ID: Hash of workspace/{real_name}

This prevents workspace enumeration while allowing consistent access.

IPC Events

The workspace service responds to IPC messages:

// Switch workspace via IPC
c.ACTION(core.Message{
    Type: "workspace.switch_workspace",
    Data: map[string]any{
        "name": workspaceID,
    },
})

Frontend Usage (TypeScript)

import {
    CreateWorkspace,
    SwitchWorkspace,
    WorkspaceFileGet,
    WorkspaceFileSet,
    ListWorkspaces,
    ActiveWorkspace
} from '@bindings/workspace/service';

// Create workspace
const wsId = await CreateWorkspace("my-project", "password");

// Switch workspace
await SwitchWorkspace(wsId);

// Read/write files
const config = await WorkspaceFileGet("config/app.json");
await WorkspaceFileSet("config/app.json", JSON.stringify(newConfig));

// List all workspaces
const workspaces = await ListWorkspaces();

// Get active workspace
const active = await ActiveWorkspace();
console.log(`Current: ${active.Name} at ${active.Path}`);