Skip to main content

Overview

The workspace is Weaver’s isolated directory structure where each agent stores its memory, session history, and operates on files. It provides the foundation for secure, multi-tenant agent deployment.

Directory Structure

A typical Weaver workspace follows this layout:
~/.weaver/workspace/
├── AGENT.md              # Agent identity and instructions
├── sessions/             # Conversation history
│   ├── cli:default.json
│   └── telegram:123.json
├── cron/                 # Scheduled tasks
│   └── jobs.json
├── .state.json           # Atomic state (last channel, etc.)
├── skills/               # Custom agent skills
│   └── weather/
│       └── SKILL.md
└── [user files]          # Agent-created files
The workspace path defaults to ~/.weaver/workspace but can be configured in config.json or overridden with Docker volume mounts.

Workspace Isolation

Weaver provides two levels of file system isolation:

Core Workspace Files

AGENT.md

Defines the agent’s identity and behavior:
# Agent Instructions

You are a helpful AI assistant. Be concise, accurate, and friendly.

## Guidelines

- Always explain what you're doing before taking actions
- Ask for clarification when request is ambiguous
- Use tools to help accomplish tasks
- Remember important information in your memory files
Edit AGENT.md to customize your agent’s personality, domain expertise, and operating procedures.

Session Files

Stored in sessions/<session-key>.json:
{
  "key": "telegram:123456",
  "messages": [
    {
      "role": "user",
      "content": "Hello!"
    },
    {
      "role": "assistant",
      "content": "Hi! How can I help you today?",
      "tool_calls": []
    }
  ],
  "summary": "",
  "created": 1704067200000,
  "updated": 1704070800000
}
Session management from pkg/session/manager.go:15-30:
type SessionManager struct {
    sessionsDir string
    cache       map[string]*Session
    mu          sync.RWMutex
}

func (sm *SessionManager) GetHistory(key string) []providers.Message {
    // Load from cache or disk
}

func (sm *SessionManager) AddMessage(key, role, content string) {
    // Add to session and mark dirty
}

func (sm *SessionManager) Save(key string) error {
    // Atomic write to disk
}
Session files are loaded lazily on first access and cached in memory. Changes are persisted immediately with atomic writes.

State File

The .state.json file stores atomic state that must survive crashes:
type Manager struct {
    workspace string
    state     *State
    mu        sync.RWMutex
}

type State struct {
    LastChannel string `json:"last_channel"` // e.g., "telegram:123456"
    LastChatID  string `json:"last_chat_id"`
}
Used by heartbeat and device notification systems:
// Record last active channel
al.state.SetLastChannel(fmt.Sprintf("%s:%s", channel, chatID))

// Later: send notification to last active channel
lastChannel := stateManager.GetLastChannel()
The state file uses atomic writes (write to temp + rename) to prevent corruption during crashes.

Workspace Configuration

Docker Volume Mounting

For isolated agent instances:
docker run --rm \
  -v $(pwd)/workspaces/agent-1:/root/.weaver/workspace \
  -e GEMINI_API_KEY=$GEMINI_API_KEY \
  operatoronline/weaver agent -m "Task description"
Each workspace is completely isolated:
workspaces/
├── agent-1/          # User A's agent
   └── sessions/
├── agent-2/          # User B's agent
   └── sessions/
└── shared-bot/       # Shared service agent
    └── sessions/

Gateway Configuration

In config.json:
{
  "workspace": {
    "path": "/root/.weaver/workspace",
    "auto_create": true
  },
  "agents": {
    "defaults": {
      "restrict_to_workspace": true
    }
  }
}
Workspace path resolution from pkg/config/config.go:
func (c *Config) WorkspacePath() string {
    if c.Workspace.Path != "" {
        return expandPath(c.Workspace.Path)
    }
    home, _ := os.UserHomeDir()
    return filepath.Join(home, ".weaver", "workspace")
}

File Operations

All file tools operate within the workspace context:
type ReadFileTool struct {
    workspace string
    restrict  bool
}

func (t *ReadFileTool) Execute(args map[string]interface{}) *ToolResult {
    path := args["path"].(string)
    
    // Resolve relative paths from workspace
    if !filepath.IsAbs(path) {
        path = filepath.Join(t.workspace, path)
    }
    
    // Check restrictions
    if t.restrict && !isWithinWorkspace(path, t.workspace) {
        return ErrorResult("Access denied")
    }
    
    content, err := os.ReadFile(path)
    return SuccessResult(string(content))
}
File tools perform atomic operations where possible (temp file + rename) to prevent corruption from interrupted writes.

Shell Execution Context

The exec tool runs commands with workspace as the working directory:
type ExecTool struct {
    workspace string
    restrict  bool
}

func (t *ExecTool) Execute(args map[string]interface{}) *ToolResult {
    cmd := exec.Command("sh", "-c", command)
    cmd.Dir = t.workspace  // Set working directory
    
    if t.restrict {
        // Set environment to prevent escaping workspace
        cmd.Env = []string{
            "HOME=" + t.workspace,
            "PWD=" + t.workspace,
        }
    }
    
    output, err := cmd.CombinedOutput()
    return SuccessResult(string(output))
}
Use cd freely in shell commands - the working directory is always the workspace by default.

Cron Jobs

Scheduled tasks are stored in cron/jobs.json:
{
  "jobs": [
    {
      "id": "job-abc123",
      "name": "Daily backup",
      "schedule": {
        "kind": "cron",
        "expr": "0 2 * * *"
      },
      "message": "Backup all important files to archive/",
      "enabled": true,
      "deliver": true,
      "channel": "telegram",
      "to": "123456"
    }
  ]
}
Manage via CLI:
# Add recurring job
weaver cron add \
  --name "Daily backup" \
  --cron "0 2 * * *" \
  --message "Backup all important files" \
  --deliver --channel telegram --to 123456

# Or interval-based
weaver cron add \
  --name "Monitor disk" \
  --every 300 \
  --message "Check disk usage and alert if >80%"

Skills Directory

Custom skills extend agent capabilities:
workspace/skills/
├── weather/
│   ├── SKILL.md          # Skill documentation
│   └── api_key.txt       # Skill-specific config
└── database/
    ├── SKILL.md
    └── schema.sql
Skills are loaded at agent startup from:
  1. Workspace skills directory (workspace/skills/)
  2. Global skills directory (~/.weaver/skills/)
  3. Built-in skills (~/.weaver/weaver/skills/)
See Skills documentation for details.

Backup and Migration

Workspace portability:
# Backup entire workspace
tar -czf agent-backup.tar.gz ~/.weaver/workspace/

# Restore on new system
tar -xzf agent-backup.tar.gz -C ~/

# Or migrate from OpenClaw
weaver migrate --refresh
Workspace directories are self-contained. Copy the entire workspace folder to migrate an agent to a new system.

Next Steps

Agent Loop

Understand how agents process messages

Skills

Learn how to create custom skills

Build docs developers (and LLMs) love