Architecture Overview
The Shokunin Platform is a Next.js 15 monorepo backed by Firebase/Firestore and Google Cloud Platform. It is built around a hierarchy of four core concepts: projects → workshops → agents → workflows.
This page explains what those concepts are, how they relate, and which parts of the system exist today versus what is planned.
Core Concepts
Project
A project is the top-level organizational unit. Every team starts by creating a project, which scopes all work: workshops, agents, task tracking (Beads), and infrastructure configuration.
Status: Implemented
- Firestore collection:
tenants/{tenantId}/projects/{projectId}
- Managed by
domains/dashboard/ (project list, creation, member management)
DashboardProject entity carries workshop count, agent count, Beads connection settings, and member list
- UI:
/projects list and /projects/[projectId] detail routes
Each project optionally connects to a Beads task-tracking database (MySQL-backed via infrastructure/beads-api or direct host config). This allows a project to track its own issue graph.
Workshop
A workshop is a managed workspace within a project where AI agents collaborate on tasks. Think of it as a room in which a team of AI agents work together, with shared context, a workflow canvas, and a knowledge base.
Status: Implemented (schema, repositories, UI routes)
- Firestore collection:
tenants/{tenantId}/projects/{projectId}/workshops/{workshopId}
- Managed by
domains/workshop/ (repositories, hooks, types)
- Core entities:
Workshop, Agent, WorkflowNode, WorkflowEdge
- UI:
/workshops, /workshops/[workshopId]/overview, /workshops/[workshopId]/agents, /workshops/[workshopId]/workflow, /workshops/[workshopId]/agent-control, /workshops/[workshopId]/settings
- Domain hooks:
useWorkshop, useAgents, useWorkflow (in domains/workshop/hooks/)
Agent Control Panel
The Agent Control Panel (/workshops/[workshopId]/agent-control) is a client-side UI that orchestrates workshop container provisioning and live session monitoring:
- Provisioning:
POST /api/workshops/[workshopId]/provision — idempotency-safe; writes status=queued to Firestore and enqueues a Cloud Tasks job for the Shokunin Provisioner. Returns 200 (no-op) when already queued/running, 202 when newly queued.
- Live session status: streams SSE events from the workshop container via
AgentRuntimeProvider (domains/agent-runtime/)
- Health indicator: polls the shokunin-agent
/status endpoint via ContainerHealthIndicator
- Deep links: per-session links to OpenCode web UI
The agentUrl field on the Workshop Firestore document is set at first provisioning and is used by the control panel for all outbound connections to the workshop container.
Workshops have a lifecycle: created within a project, configured with agents, and executed by running workflows. A workshop belongs to exactly one project.
Agent
An agent is an AI participant in a workshop. Agents have specializations (e.g., Architect, Developer, DBA, QA), a model assignment, a system prompt, and a status (idle | working | error | active | disabled).
Status: Implemented (schema, repository, agent management UI)
- Firestore collection:
.../workshops/{workshopId}/agents/{agentId}
- Repository:
domains/workshop/repositories/agent-repository.ts
- Agents are created through the workshop’s agent management UI
- Specializations: Architect, Developer, DBA, DevOps, QA, Security, Tech Lead, Product Owner
- Plan limits enforced in UI (disabled button + upgrade banner when at limit)
Agents appear in collaboration surfaces with the same presence semantics as human users — avatars, activity dots, and canvas ownership badges.
There are two distinct agent concepts in the platform:
Shokunin Agent (Autonomous Service)
The Shokunin Agent (infrastructure/shokunin-agent) is an autonomous TypeScript service that runs inside a Workshop Container alongside OpenCode. It manages the full agent lifecycle: polling Beads for ready tasks, creating isolated git worktrees per task, spawning OpenCode sessions, and persisting state to Firestore.
- Replaces the
agent-loop.sh bash script
- Built on Fastify with structured logging (pino), listening on port 8090
- Talks to OpenCode (port 4096, same pod) via
@opencode-ai/sdk
- Listens for
session.idle / session.error SSE events from client.global.event() as completion signals
- Exposes a control REST API (
POST /loop/start, POST /loop/stop, GET /status) authenticated via X-Agent-Key
- Proxies
/opencode/* requests to OpenCode including SSE streaming (piped without buffering)
- Can be scoped to a specific Beads epic (
epicId) to work on a subset of tasks
- Persists runtime state (
AgentRuntimeState, SessionMapping) to Firestore at agents/{agentId}/runtime/state
- Externally reachable via a shared GKE Gateway at
agent.<tenant>.<domain>
Status: Implemented — See tasks/prd-shokunin-agent-service.md for the full PRD.
Forge Agent
A Forge Agent is an agent specialized in code review and merge operations — designed to validate and integrate agent-produced changes into the main branch via a dedicated workflow. Forge agents operate on git worktrees produced by other sessions.
Status: Planned — Referenced in Shokunin Agent Service PRD as future integration point.
Workflow
A workflow is a directed graph of steps that agents execute inside a workshop. Workflows are built visually using a React Flow canvas and persisted in Firestore.
Status: Implemented (schema, repositories, canvas UI)
- Firestore collections:
.../workflowNodes/{nodeId} and .../workflowEdges/{edgeId}
- Repositories:
domains/workshop/repositories/workflow-node-repository.ts, workflow-edge-repository.ts
- Node types (from
packages/shokunin-flow): StartNode, StepNode, ConditionNode, LoopNode, ParallelNode, EndNode
- Edge types:
FlowEdge, ConditionalEdge, LoopbackEdge
- Each
StepNode can have an assigned agent from the workshop’s agent pool
- Mock data: SDLC workflow (Plan → Design → Implement → Review → Test → Deploy) seeded on creation
In Progress: Live workflow execution — today, workflows define what should happen. The Shokunin Agent Service is implemented and can execute tasks via OpenCode; dispatching specific workflow step nodes to agents based on workflow graph traversal is the remaining integration point.
System Architecture
The diagram below shows the full system: the platform UI running in the browser backed by Firebase, and the planned Workshop Container where autonomous agents execute tasks using OpenCode and Beads.
Domain Model
The platform organizes Firestore data into four domain modules:
| Domain | Location | Status |
|---|
| Dashboard (Projects) | domains/dashboard/ | Implemented |
| Workshop, Agents, Workflow | domains/workshop/ | Implemented |
| Beads (Task Tracking) | domains/beads/ | Implemented |
| Agent Runtime | domains/agent-runtime/ | Implemented |
| Infrastructure Status | domains/infrastructure/ | Implemented |
| Shokunin Agent Service | infrastructure/shokunin-agent/ | Implemented |
Firestore Collection Hierarchy
tenants/{tenantId}/
projects/{projectId} ← DashboardProject
workshops/{workshopId} ← Workshop (agentUrl field set at provision time)
agents/{agentId} ← Agent
runtime/state ← AgentRuntimeState (written by shokunin-agent)
workflowNodes/{nodeId} ← WorkflowNode
workflowEdges/{edgeId} ← WorkflowEdge
provisioning/state ← ProvisioningRecord (queued → running → succeeded/failed)
All Firestore documents carry versioning metadata (schemaVersion, createdAt, updatedAt, tenantId) and support on-read lazy migrations via a shared migrations framework.
Agent Runtime domain
domains/agent-runtime/ provides a provider-agnostic interface for consuming agent events in the browser:
AgentRuntimeProvider interface (types.ts) — factory-based, not class-based; structural compatibility over inheritance
createOpenCodeProvider (providers/opencode-provider.ts) — connects to <agentBaseUrl>/opencode/event SSE stream, reconnects automatically on disconnect
- Pure utilities:
event-parser.ts (parses raw SSE strings into typed SessionEvent objects), health-mapper.ts (mapStatusResponseToHealth maps HTTP health check responses to HealthState)
- Used by:
ContainerHealthIndicator, AgentControlPanel
Infrastructure Status domain
domains/infrastructure/ provides GCP infrastructure status data to the Admin Infrastructure Dashboard:
GcpStatusRepository interface + createHttpGcpStatusRepository() HTTP implementation (calls /api/infrastructure/status)
useInfrastructureStatus(env) hook — fetches and auto-refreshes every 60 seconds; manages loading/error state
environment-resolver.ts — pure function that resolves EnvironmentContext from process.env (reads NEXT_PUBLIC_FIREBASE_DATABASE_ID)
manifest-parser.ts — pure stateless functions for querying GcpInfraManifest declarations
Package Architecture
Internal packages under packages/ provide shared primitives:
| Package | Purpose | Status |
|---|
shokunin-types | Shared TypeScript types | Implemented |
shokunin-ui | Shared UI component library | Implemented |
shokunin-flow | React Flow workflow canvas nodes/edges | Implemented |
shokunin-feature-flags | Static feature flag provider | Implemented |
shokunin-auth | Auth provider and hooks | Implemented |
shokunin-ai | AI provider interface (stub) | Implemented (stub) |
shokunin-collaboration | Collaboration/presence adapter (stub) | Implemented (stub) |
shokunin-cms | CMS adapter | Implemented |
Infrastructure
| Component | Technology | Status |
|---|
| Web App | Next.js 15, Vercel | Implemented |
| Database | Google Firestore | Implemented |
| Auth | Firebase Authentication | Implemented |
| Task Tracking API | infrastructure/beads-api (Fastify + MySQL) | Implemented |
| OpenCode Web | infrastructure/opencode-web (Docker) | Implemented (scaffold) |
| Workshop Container | Docker (shokunin-agent + opencode) | Implemented |
| Shokunin Agent Service | infrastructure/shokunin-agent/ (Fastify + TypeScript) | Implemented |
| Workshop Provisioner | infrastructure/shokunin-provisioner/ (Fastify + Cloud Run) | Implemented |
| GKE Gateway (shared) | GKE Gateway API + Certificate Manager | Implemented |
| Infrastructure Dashboard | app/(platform)/admin/infrastructure/ + domains/infrastructure/ | Implemented |
| IaC | Terraform on GCP | Implemented |
Data Flow: From Task to Code
End-to-end flow for autonomous task execution via the Shokunin Agent Service.
External routing (Vercel → Workshop)
Vercel (platform UI)
│ HTTPS
▼
GKE Gateway (shared, TLS termination)
│ hostname-based routing
├──► agent.<tenant>.<domain> → Workshop Service :8090 (shokunin-agent REST + proxy)
└──► opencode.<tenant>.<domain> → Workshop Service :4096 (OpenCode web API)
Workshop Pod (GKE Autopilot)
├── shokunin-agent (port 8090) ←── task polling, session control, Firestore state
└── opencode (port 4096) ←── code execution sessions (SSE events)
The agentEndpoint stored in Firestore for each workshop is the external Gateway URL (e.g., https://agent.acme-corp.example.com) — not an in-cluster address.
Task execution flow
- User creates a project, workshop, configures agents and a workflow in the platform UI.
- Beads tracks the task graph for the project.
- Shokunin Agent (
POST /loop/start) polls Beads for ready tasks (bd ready).
- For each ready task, the agent creates an isolated git worktree (
<repo>/.worktrees/task-<id>, branch agent/task-<id>).
- The agent spawns an OpenCode session scoped to that worktree directory via
client.session.create({ query: { directory } }).
- OpenCode works autonomously; the agent listens for
session.idle / session.error SSE events on client.global.event().
- On
session.idle (completion): the agent runs bd sync, cleans up the worktree, and updates Firestore state.
- On
session.error (failure): the agent cleans up the worktree and records the error in Firestore.
- A Forge Agent (planned) reviews the produced branch and merges it.
- The platform UI reflects the updated task status in real time via Firestore.
The agent listens for session.idle (not session.updated) as the completion signal. session.updated carries only metadata changes and must not be used as a terminal event.
Key Design Decisions
Repository Pattern
Data access is encapsulated in repository classes under domains/<domain>/repositories/. Business logic never touches Firestore directly.
Domain Hooks
Custom React hooks (useWorkshop, useAgents, useWorkflow) consume repositories and expose reactive state. Context (tenantId, projectId) is injected explicitly, not read from global state.
Server vs Client Components
Server Components are used by default. 'use client' is added only when interactivity (state, events) is strictly required.
Worktree Isolation
The planned Shokunin Agent Service assigns one git worktree per task. This prevents file conflicts between concurrent agent sessions and enables parallel task execution as a future capability.