NX

From Chat to Cowork: File-Folder-Driven Agentic Workflows in Your Go Backend

🛠️ 开发者实操 x/dev-workshop ·
From Chat to Cowork: File-Folder-Driven Agentic Workflows in Your Go Backend

Chat to Cowork

Not another AI chatbot. This is a battle-tested architecture guide extracted from Claude Cowork — turning your LLM agent from a conversational partner into a team member that delivers finished work. Updated with coworkspace naming conventions to avoid conflicts with existing workspaces infrastructure.


Why Move From Chat to Cowork?

Rahul recently dropped a viral post on X — "How To Build a One-Person Company Using Claude Cowork" — racking up over 850K views. His core insight was devastatingly simple:

The average knowledge worker spends 60% of their day on work that doesn't require deep thought: formatting, organizing files, compiling reports, researching, SEO. The heavy lifting is the assembly, not the thinking.

Chat-based AI is useful, but it has a fundamental limitation: you're in the loop for every single turn. Every action requires your next prompt. That's collaboration — not delegation.

Claude Cowork changes the equation. Its core insight: wrap Claude Code's agentic engine in a GUI, and non-technical users can delegate entire tasks.

But if you're a developer, you don't need a "how to use Claude Cowork" tutorial. You need: how to implement the same architecture in your own Go backend.

This article is that implementation guide.


The Five Design Patterns Claude Cowork Gets Right

After deep-diving into Cowork's architecture, I extracted five patterns you can migrate to any backend:

1. Outcome-First, Not Prompt-First

Traditional Chat: user breaks down the problem → prompts step by step → AI responds step by step
Cowork mode: user describes the desired result → AI autonomously plans → executes → delivers

// Traditional Chat API
POST /api/chat { "message": "Organize my Downloads folder" }

// Cowork API (using coworkspace slug instead of opaque ID)
POST /api/cowork/tasks {
  "outcome": "Organize Downloads folder by type and date. Extract receipts and generate an expense report.",
  "coworkspace_slug": "downloads-organizer"
}

2. Coworkspace = File Folder (Slug-Based)

Every task has a corresponding folder. Files are the medium of exchange between human and agent. The agent reads, processes, and writes — the user returns to finished deliverables.

Why coworkspaces instead of workspaces? If your codebase already has a workspaces directory or concept, coworkspaces avoids namespace collisions entirely. Similarly, using slugs (e.g., downloads-organizer) instead of opaque IDs makes folders readable by both humans and agents — your filesystem becomes self-documenting.

/coworkspaces/{slug}/
├── .instructions.md       ← Project instructions (claude.md equivalent)
├── .memory/               ← Agent memory (persists across sessions)
├── .plan.json             ← Current task plan
├── files/                 ← User files
├── output/                ← Agent-generated deliverables
└── .locks/                ← File locks (prevents race conditions)

3. Plan First, Execute Second

The agent doesn't blindly start working. It generates a visible, reviewable plan:

{
  "summary": "Organize Downloads and generate expense report",
  "phases": [
    {
      "name": "Scan and Classify",
      "subtasks": ["List all files", "Group by extension", "Create category folders"],
      "parallel": false
    },
    {
      "name": "Parallel Processing",
      "subtasks": ["Process receipt PDFs", "Organize images", "Archive documents"],
      "parallel": true
    },
    {
      "name": "Generate Report",
      "subtasks": ["OCR receipts", "Extract amounts and dates", "Generate Excel report"],
      "parallel": false,
      "depends_on": ["Parallel Processing"]
    }
  ]
}

Users can review and modify the plan before execution begins. This is transparent autonomy.

4. Sub-Agent Fan-Out

Complex tasks aren't run by a single agent from start to finish. Based on parallel: true phases, the orchestrator spawns multiple sub-agents simultaneously:

Main Agent (Orchestrator)
  ├── Agent A: Process receipt PDFs
  ├── Agent B: Organize image files
  ├── Agent C: Archive document files
  └── Agent D: Deduplicate and clean up

  All done →
  Main Agent synthesizes results → generates final deliverables

Each sub-agent gets its own context window and communicates through files and messages — not shared memory. This prevents context pollution and keeps each agent focused.

5. Checkpointing Enables Long-Running Tasks

Cowork tasks can run for minutes or hours. State must be saved at every turn:

type TaskCheckpoint struct {
    TaskID       string             `json:"task_id"`
    Turn         int                `json:"turn"`
    AgentStates  []AgentSnapshot    `json:"agent_states"`
    PlanProgress map[string]float64 `json:"plan_progress"`
    SavedAt      time.Time          `json:"saved_at"`
}

Server restart? Tasks resume from the last checkpoint. This is the fundamental difference between Chat and Cowork — Chat dies and restarts from zero; Cowork picks up where it left off.


Go Backend Architecture: From Chat to Chat + Cowork

Your Existing Foundation

The good news: your Go backend already has most of the building blocks:

Existing Feature Cowork Counterpart
Chat Cowork Task (assign outcomes, not conversation)
Goals Task Plan (visible to-do list with phases)
Files-based projects Coworkspace (persistent folder per task)
Direct tasks (async) Agent Loop (autonomous multi-step execution)
Schedules Scheduled Cowork Tasks (cron + manual trigger)

The Four Core Services (All Coworkspace-Prefixed)

// 1. CoworkOrchestrator — full task lifecycle
type CoworkOrchestrator interface {
    CreateTask(ctx, outcome, coworkspaceSlug, opts) (*CoworkTask, error)
    StartTask(ctx, taskID) error
    GeneratePlan(ctx, taskID) (*TaskPlan, error)
    GetTaskProgress(ctx, taskID) (*TaskProgress, error)
}

// 2. AgentLoop — the autonomous execution engine
type AgentLoop interface {
    ExecuteTurn(ctx, agentID) (*TurnResult, error)
    ExecuteUntilDone(ctx, agentID, opts) error
}

// 3. SubAgentOrchestrator — parallel sub-agent management
type SubAgentOrchestrator interface {
    FanOut(ctx, taskID, specs) ([]SubAgent, error)
    ClaimTask(ctx, taskID, subtaskID, agentID) error
    SynthesizeResults(ctx, taskID) (*SynthesisResult, error)
}

// 4. CoworkspaceManager — file-folder workspace management
type CoworkspaceManager interface {
    CreateCoworkspace(ctx, name, opts) (*Coworkspace, error)
    ReadFile(ctx, coworkspaceSlug, path) ([]byte, error)
    WriteFile(ctx, coworkspaceSlug, path, content) error
}

Agent Loop — The Heart of the System

The Agent Loop is the state machine that turns "I want X" into a series of LLM-powered actions:

LOOP:
  1. Build Prompt (task + plan + current state + available tools)
  2. Call LLM → receive Thought + Tool Calls
  3. Approval Gate (high-risk operations require user confirmation)
  4. Execute Tools (read, write, search, generate...)
  5. Feed results back to agent
  6. Check termination: done / wait_for_user / continue
  7. Save Checkpoint
GOTO LOOP

The core Tool Registry:

var CoreCoworkTools = []Tool{
    FileReadTool{},           // Read coworkspace files
    FileWriteTool{},          // Write/create files
    FileListTool{},           // List directory contents
    WebSearchTool{},          // Web search
    WebFetchTool{},          // Fetch URL content
    ShellTool{},             // Execute in sandbox
    SubAgentSpawnTool{},     // Launch sub-agent
    SubAgentMessageTool{},   // Inter-agent communication
    MemoryStoreTool{},       // Save to coworkspace memory
    MemoryRetrieveTool{},    // Retrieve from coworkspace memory
    TaskUpdateTool{},        // Update task plan
    DeliverableCreateTool{}, // Create deliverables
}

Database Schema (All Coworkspace-Prefixed)

-- Coworkspaces (slug-based instead of ID-based)
CREATE TABLE coworkspaces (
    slug          TEXT PRIMARY KEY,       -- e.g., "downloads-organizer"
    name          TEXT NOT NULL,
    root_path     TEXT NOT NULL,
    instructions  TEXT,
    project_id    TEXT,
    user_id       TEXT NOT NULL,
    created_at    TIMESTAMP DEFAULT NOW()
);

-- Cowork Tasks
CREATE TABLE cowork_tasks (
    id                TEXT PRIMARY KEY,
    coworkspace_slug  TEXT NOT NULL REFERENCES coworkspaces(slug),
    outcome           TEXT NOT NULL,
    status            TEXT NOT NULL DEFAULT 'pending',
    plan_json         JSONB,
    permission_mode   TEXT NOT NULL DEFAULT 'ask_before'
);

-- Task Phases
CREATE TABLE task_phases (
    id         TEXT PRIMARY KEY,
    task_id    TEXT NOT NULL REFERENCES cowork_tasks(id),
    name       TEXT NOT NULL,
    status     TEXT NOT NULL DEFAULT 'pending',
    parallel   BOOLEAN DEFAULT FALSE,
    depends_on JSONB,
    progress   REAL DEFAULT 0.0
);

-- Sub-Agents
CREATE TABLE sub_agents (
    id      TEXT PRIMARY KEY,
    task_id TEXT NOT NULL REFERENCES cowork_tasks(id),
    name    TEXT NOT NULL,
    role    TEXT NOT NULL,
    status  TEXT NOT NULL DEFAULT 'idle'
);

-- Agent Messages (inter-agent communication)
CREATE TABLE agent_messages (
    id         TEXT PRIMARY KEY,
    from_agent TEXT NOT NULL,
    to_agent   TEXT NOT NULL,
    type       TEXT NOT NULL,
    content    TEXT NOT NULL
);

-- Task Checkpoints (for crash recovery)
CREATE TABLE task_checkpoints (
    id         TEXT PRIMARY KEY,
    task_id    TEXT NOT NULL REFERENCES cowork_tasks(id),
    turn       INTEGER NOT NULL,
    state_json JSONB NOT NULL
);

-- Indexes
CREATE INDEX idx_cowork_tasks_coworkspace ON cowork_tasks(coworkspace_slug);
CREATE INDEX idx_cowork_tasks_status ON cowork_tasks(status);
CREATE INDEX idx_phases_task ON task_phases(task_id);
CREATE INDEX idx_agents_task ON sub_agents(task_id);
CREATE INDEX idx_checkpoints_task ON task_checkpoints(task_id, turn DESC);

Incremental Migration Path

No need to tear everything down. Cowork is additive to Chat, not a replacement:

Phase 1: Foundation (Weeks 1-2)

  • Implement CoworkspaceManager + file CRUD at /coworkspaces/{slug}/
  • Add CoworkTask data model and API endpoints
  • Add .instructions.md support

Phase 2: Agent Loop (Weeks 3-4)

  • LLM + Tool Calling integration
  • Turn-by-turn agent execution
  • Plan generation + approval gate

Phase 3: Orchestration (Weeks 5-6)

  • Sub-agent spawning and management
  • File-lock-based task claiming
  • Inter-agent messaging + result synthesis

Phase 4: Polish (Weeks 7-8)

  • SSE real-time progress streaming
  • Integration with existing Schedules system
  • Checkpoint/restore for long-running tasks

Throughout this process, your existing Chat API remains completely untouched. Users can use both modes simultaneously.


Key Design Decisions

Decision Rationale
Coworkspace = file folder Files are the most natural medium of exchange between human and agent
Slug-based routing Human-readable paths (/coworkspaces/downloads-organizer/), no opaque IDs
coworkspaces directory Avoids conflicts with existing workspaces naming in the codebase
cowork_* / coworkspace_* prefix Clean namespace isolation for all tables, functions, and routes
Plan-first execution Transparency + user can course-correct before work begins
Disposable sub-agents Independent contexts, communicate via files — no context pollution
Checkpoint every turn Crash recovery, long-running task resumability
Configurable approval ask_before (safe) vs act_autonomously (fast); file deletion always requires approval
Chat stays unchanged Cowork is addition, not substitution — use the right tool for the job

Summary

Claude Cowork doesn't mean you need to replace your backend. It represents a shift in architectural thinking:

  • From "I tell the AI every step" to "I tell the AI what outcome I want"
  • From a chat box to a file folder
  • From a single agent to an agent team
  • From synchronous waiting to asynchronous delegation

Your existing Go backend already has Chat, Schedules, Goals, Files, and Direct Tasks — these are the perfect foundation for the Cowork pattern. Add an Agent Loop, a Sub-Agent Orchestrator, and Coworkspace management, and your LLM agent transforms from a passive conversation partner into a team member that independently delivers finished work.


Sources

·