Workshop Manual
The usage and development dimensions of the three workshops: Creative Workshop (recipe/flow), Skill Workshop, Skill Forge, Skill Proposals, Broker Workshop. Source:
OPERATION.md§19–§20, §37–§38,src/bridge/routes/skill_forge.py,skill_proposals.py,skill_workshop.py,agent_recipes.py,flow_templates.py.
Table of Contents
- Skill Forge
- SKILL.md Format Specification
- Skill Change Approvals
- Skill Workshop
- Creative Workshop (Recipe)
- Creative Workshop (Flow)
- Recipe Compile / Dry-run / E2E Test
1. Skill Forge
Component: SkillForgeModal.vue
Entry: ChatStage multi-select messages (Shift/Ctrl) → top batch action bar → Forge Skill
1.1 Backend API (src/bridge/routes/skill_forge.py)
| Endpoint | Phase | Description |
|---|---|---|
POST /derive_io | Phase 1 fast path | Single LLM rewrite → parse INPUTS/OUTPUTS/TRIGGER lines → ~30-40s |
POST /propose | Phase 1 full | rewrite + tool_select + denoise + params + mock + summary → ~12min |
POST /repropose | Phase 1 re-propose | Regenerate summary after user locks I/O |
POST /build_and_preview | Phase 2 | Full chain: denoise → tool_select → params → mock → summary → generate → validate → repair |
POST /preview | Phase 2 legacy | Generate SKILL.md + validate |
POST /revise | Revise | Agent mode tool loop (read/grep/edit/validate/finish) |
POST /commit | Commit | Persist SKILL.md + refresh skill_registry.json |
GET /revise/inflight | Query | List of skill_ids currently being revised |
GET /revise/terminal/<skill_id> | Query | Consume completed revision results |
1.2 3-Step Wizard Flow
Step 1 — params (parameter confirmation)
- Frontend
POST /derive_io→ backend single LLM rewrite (workspace/skills/prompts/forger_rewrite.md) → parse intent'sINPUTS:/OUTPUTS:/TRIGGER:lines → returns{intent, inputs, outputs, trigger, skill_id_seed} - Shows three editable areas:
- Input list: Each row
{name, type, description}, can add/delete/modify - Output list: Same as above
- Trigger scenarios: Text input
- Input list: Each row
- Floating buttons appear after user changes:
- ✕ Revert: Restore LLM original (baselineInputs/baselineOutputs/baselineTrigger)
- ✓ Apply:
POST /repropose→ backend regenerates summary with locked I/O
Step 2 — review
POST /build_and_preview→ backend runs full chain → returns{skill_md, errors, skill_id, summary}- Shows full SKILL.md preview (markdown rendered)
- Editable:
skill_id: snake_case,^[a-z][a-z0-9_]{0,63}$scope:global/agent/recipe(defaults to recipe when agent is bound to recipe)overwrite: overwrite toggle for same-name conflicts
- If
errorspresent, shown in red list:input_missing: Locked input name not found in SKILL.mdoutput_missing: Locked output name not found in SKILL.mdscript_still_invalid: Embedded script I/O contract mismatchpipeline_validator_crashed: Pipeline validator exception
- Can enter
user_guidance→POST /revise→ agent mode revision
Step 3 — commit
- Click Submit →
POST /commit→ writes to target directory:global→workspace/skills/<skill_id>/SKILL.mdagent→workspace/agents/agent_<id>/skills/<skill_id>/SKILL.mdrecipe→workspace/agent_recipes/<recipe_id>/skills/<skill_id>/SKILL.md
- Refreshes
skill_registry.json(rebuild_skill_registry) - If registry did not pick it up (empty description causes indexer to skip), falls back to injecting a placeholder entry
- Clears
dense_recallcache
1.3 Phase 1 vs Phase 2 Data Flow
Phase 1 (derive_io):
User selects messages → POST /derive_io → single LLM rewrite → parse I/O
User confirms/edits I/O → (optional) POST /repropose → LLM re-summarizes
Phase 2 (build_and_preview):
POST /build_and_preview →
Round 1: denoise (trace denoising)
Round 2: tool_select + params (parallel)
Round 3: mock (simulate inputs)
Round 4: summary
Round 5: generate (complete SKILL.md)
→ validate (structural validation) + repair (one repair attempt)
→ I/O name presence check
→ per-script I/O validate + repair
→ pipeline gate
→ returns {skill_md, errors}2. SKILL.md Format Specification
2.1 Basic Structure
---
skill_id: my_skill
description: One-line description
version: 1.0
tags:
category: productivity
trigger_scenarios:
intent:
- User says "help me generate a report"
condition:
- Agent has access to the reporting system
---
## Skill Inputs
```json
{
"type": "object",
"properties": {
"report_type": {"type": "string", "description": "Report type"},
"date_range": {"type": "string", "description": "Date range"}
},
"required": ["report_type"]
}Skill Outputs
{
"type": "object",
"properties": {
"report_content": {"type": "string"},
"file_path": {"type": "string"}
}
}Step 1: Collect Data
Input Schema (JSON):
{"properties": {"query": {"type": "string"}}, "required": ["query"]}Instructions: Use the search tool to find relevant information... Output Schema (JSON):
{"properties": {"results": {"type": "array"}}}Step 2: Generate Report
...
### 2.2 Validation Rules (`SkillForger.validate()`)
1. **Topology validation**: Metadata → Skill Inputs → Skill Outputs → Steps → correct order
2. **Field name exact match**: Step Input Schema property names must match SKILL-level Inputs or upstream Step Outputs (no fallback)
3. **Tool step I/O 1:1 SET match**: Each tool step's Input Schema must be a subset of the target tool's parameters; Output Schema must be a subset of the tool's return values
### 2.3 Validator EndpointsPOST /api/skills/forge/preview → {skill_md, errors} POST /api/skills/forge/commit → validate first, then pipeline_gate, then write
**pipeline gate** (`_validate_skill_source`): Checks the full data flow contract — every step input must be resolvable from prior step outputs or skill inputs, every step output must be consumed downstream or emitted as a skill output.
### 2.4 Embedded Script Validation
` ```python ` / ` ```bash ` code blocks inside SKILL.md (≥300 bytes) are extracted and validated for I/O contract:
- Script must read inputs from `skill_inputs`
- Script must write results to `skill_outputs`
- Validation failure → one LLM repair attempt
- Still fails after repair → `script_still_invalid` error
### 2.5 Revision Mode (`POST /revise`)
User provides `user_guidance` → `SkillReviseAgent` tool loop:
- `read_skill`: Read current SKILL.md
- `grep_skill`: Search content
- `edit_skill`: Edit SKILL.md
- `validate_skill`: Call validator
- `finish`: Complete revision
Up to `MAX_TURNS` rounds. After revision, placeholder expansion + final gate is executed.
---
## 3. Skill Change Approvals (SkillProposals)
**Component**: `SkillApprovalsView.vue`
**Entry**: Desktop → **Skill Change Approvals** icon (`skill-approvals` app)
**Backend**: `src/bridge/routes/skill_proposals.py`
### 3.1 API Endpoints
| Endpoint | Description |
|---|---|
| `GET /api/skill_proposals` | List all pending proposals (no body, metadata only) |
| `GET /api/skill_proposals/count` | Pending count (for DialogList badge) |
| `GET /api/skill_proposals/<pid>` | Full proposal (with current_body + proposed_body) |
| `POST /api/skill_proposals/<pid>/approve` | Approve → writes to `workspace/skills/` |
| `POST /api/skill_proposals/<pid>/reject` | Reject → archives to `rejected/` |
### 3.2 Approval Queue Storage
- Queue location: `workspace/manager/skill_proposals/pending/`
- Each proposal is one JSON file: `{proposal_id}.json`
- Fields: `proposal_id`, `target_agent_id`, `skill_id`, `target_path`, `created_at`, `trigger`, `current_body`, `proposed_body`, `run_id`, `report_path`
### 3.3 Trigger Condition
When agent's `skill_auto_apply=False` (default) → agent's SKILL.md modifications via `manager_review_tools.apply_agent_updates` enter the approval queue.
### 3.4 Interface Interactions
- List: Each entry shows source agent (`agentName(agentId)`), `skill_id`, `created_at`
- Expanded diff: `current_body` vs `proposed_body` side-by-side comparison
- **Approve**: `approve_proposal(pid)` → writes SKILL.md
- **Reject**: Enter reason → `reject_proposal(pid, reason)` → moves to `rejected/`
- Auto-refresh: 6-second polling (`store.loadPendingSkillProposals()`)
---
## 4. Skill Workshop (SkillWorkshop)
**Component**: `SkillWorkshop.vue` (top-level) + sub-components
**Entry**: Desktop → **Skill Workshop** icon (`skill-workshop` app)
**Targeted at**: Long-flow, manager-only skills requiring step-by-step feedback
### 4.1 Backend API (`src/bridge/routes/skill_workshop.py`)
| Endpoint | Description |
|---|---|
| `GET /api/skill_workshop/skills` | List manager skills with `has_form_component` |
| `POST /api/skill_workshop/upload` | Multipart upload reference images/videos/audio |
| `GET /api/skill_workshop/asset?path=...` | Read files from session/run directories |
| `POST /api/skill_workshop/rewrite` | LLM rewrite storyboard (chunked, bucketed by token budget) |
| `POST /api/skill_workshop/run` | Start runner (background thread) |
| `GET /api/skill_workshop/run/<run_id>/status` | Poll status.json |
| `GET /api/skill_workshop/run/<run_id>/images` | List all involved images (character refs + keyframes) |
| `POST /api/skill_workshop/run/<run_id>/regenerate_image` | Regenerate a single image |
| `POST /api/skill_workshop/run/<run_id>/approve_images` | Approve images → advance to clip_review |
| `GET /api/skill_workshop/run/<run_id>/clips` | List per-clip status |
| `POST /api/skill_workshop/run/<run_id>/clips/<idx>/generate` | Generate a single clip |
| `POST /api/skill_workshop/run/<run_id>/concat_final` | Concatenate all clips → final.mp4 |
| `GET /api/skill_workshop/draft` | Read resume draft |
| `POST /api/skill_workshop/draft` | Save resume draft |
| `GET /api/skill_workshop/history/<skill_id>` | Historical run list |
| `GET /api/skill_workshop/history/<skill_id>/<run_id>` | Single run details |
### 4.2 State Machine (6+ phases)pick → compose → review → running → image_review → clip_review → done ↘ error ↕ history (entered from pick or done)
| Phase | Component | Description |
|---|---|---|
| `pick` | Main page | Registered manager skill list + **History** button |
| `compose` | `GenerateVideoForm.vue` / `EditVideoForm.vue` | Input form: topic/duration/characters/scenes/reference images |
| `review` | `StoryboardReview.vue` | LLM-rewritten storyboard → user can edit each segment's prompt |
| `running` | Progress panel | Polls status.json, shows Phase A (image generation) progress |
| `image_review` | `ImageReview.vue` | Grid display of all involved images → per-image edit prompt / regenerate |
| `clip_review` | `ClipReview.vue` | Each clip has individual **Compose** button → final **Export Video** |
| `done` | Video player | Displays final.mp4 |
| `error` | Error panel | Shows error message + **Back** button |
| `history` | History list | Historical run list + details + **Use as Template** to backfill form |
### 4.3 generate_video Full Flow
1. **compose**: Fill in `GenerateVideoForm.vue`
- Topic, duration (5-300 seconds), whether to add voiceover
- Character list: name + description + reference image upload (≤4MB, PNG/JPEG/WebP)
- Object/scene references: name + kind(object/scene/character) + description + reference image
- Scene list: duration(3-15) + script(≥20 chars) + first_frame_prompt + last_frame_prompt
- Optional: upload keyframe images / upload full video clip
- Optional: aspect ratio (16:9 / 1:1 / 9:16)
- LocalStorage auto-saves drafts
2. **rewrite**: `POST /rewrite` → chunked LLM rewrite
- Scenes bucketed by token budget (~2700 tokens/bucket)
- Each bucket gets independent LLM call → only rewrites scenes within that bucket
- User-uploaded keyframes/clips marked `__pass_through__: true` → LLM copies verbatim
- Returns storyboard JSON + warnings
3. **review**: `StoryboardReview.vue` display → user edits prompts → click **Approve**
4. **run**: `POST /run` → `start_generate_video_run()` → background thread
- run_id: `vid_<ts>_<sha256(storyboard)[:10]>`
- Assets stored in `workspace/manager/skill_workshop_runs/<run_id>/`
- status.json records state
5. **image_review**: `GET /run/<id>/images` → grid display → per-image edit/regenerate
- `POST /regenerate_image` → `force_intense_mode()` bypasses approval → synchronous regeneration
- `POST /approve_images` → state advances to `awaiting_clip_review`
6. **clip_review**: `GET /run/<id>/clips` → each clip has independent **Compose** button
- `POST /clips/<idx>/generate` → synchronous single clip generation
- `POST /concat_final` → concatenate all clips → final.mp4
### 4.4 Upload Limits
| Role | MIME | Max Size |
|---|---|---|
| character / first_frame / last_frame | PNG/JPEG/WebP | 4MB |
| clip / edit_asset_video | MP4/MOV/WebM/MKV | 100MB |
| edit_asset_audio | MP3/WAV/AAC/FLAC/OGG | 30MB |
| scene_ref | PNG/JPEG/WebP | 4MB |
Character/first-frame/last-frame uploads are automatically `strip_white_inplace` processed (remove edge white → RGBA PNG).
### 4.5 Resume Mechanism
- Frontend draft → `POST /draft` → persisted to `workspace/manager/skill_workshop_runs/resume_draft.json`
- App restart → `GET /draft` → restores storyboard + run_id
- run_id determinism: `sha256(canonical storyboard JSON)[:10]` → same storyboard → same run_id → resume rather than restart
---
## 5. Creative Workshop (Recipe)
**Component**: `CreativeWorkshop.vue`
**Entry**: Desktop → **Creative Workshop** icon (`workshop` app → `WorkshopApp.vue` → `CreativeWorkshop.vue`)
**What is a Recipe**: A custom new agent architecture formed by module substitution / full replacement on top of the Familiars pipeline. Recipes are the automated orchestration of skills (LLM + tool graph).
### 5.1 Backend API (`src/bridge/routes/agent_recipes.py`)
| Endpoint | Description |
|---|---|
| `GET /api/recipes/catalog` | Tool catalog (all available tool schemas) |
| `GET /api/recipes` | Recipe list |
| `POST /api/recipes` | Create new recipe |
| `GET /api/recipes/<id>` | Get full recipe (manifest + sidecar files) |
| `PUT /api/recipes/<id>` | Save recipe (partial update sidecar) |
| `DELETE /api/recipes/<id>` | Delete recipe |
| `POST /api/recipes/<id>/bind/<agent_id>` | Bind to agent |
| `POST /api/recipes/<id>/unbind/<agent_id>` | Unbind from agent |
| `POST /api/recipes/<id>/duplicate` | Copy recipe |
| `GET /api/recipes/<id>/export` | Download .recipe.zip |
| `POST /api/recipes/import` | Upload .recipe.zip |
| `POST /api/recipes/import-folder` | Import from folder |
| `POST /api/recipes/<id>/compile` | Compile validation |
| `POST /api/recipes/<id>/dryrun` | Dry-run test |
| `POST /api/recipes/<id>/e2e-test` | E2E end-to-end test |
| `GET /api/recipes/<id>/knowledge/<path>` | Read knowledge base file |
| `GET /api/recipes/default` | Get default recipe |
| `PUT /api/recipes/default` | Set default recipe |
| `DELETE /api/recipes/default` | Clear default |
### 5.2 Recipe Data Structure
```json
{
"manifest": {
"id": "my_recipe",
"name": "My Recipe",
"description": "...",
"version": "1.0",
"capabilities": {
"extra_modules": ["requests", "sqlite3"]
},
"state_graph": {
"nodes": [...],
"edges": [...]
},
"output_renderers": [...]
},
"user_code": {"filename.py": "source..."},
"knowledge": {"AGENTS.md": "content..."},
"skill_templates": {"skill_name": "SKILL.md content..."},
"external_kb": {"kb_name": {"filename": "content..."}},
"schemas": {"schema.json": "{...}"},
"assets_b64": {"figure.png": "base64..."}
}5.3 Interface Layout
Top bar:
- Protocol: File path conventions for imported folders/zips
- Import zip / Import folder: Quick-import to generate Recipe
- Export zip: Package as importable zip
- Save: Save current Recipe
- Copy: Clone as new Recipe
- Delete: Delete current Recipe
- Upload (Relay): One-click upload to relay marketplace
Left sidebar list:
- All Recipes listed by group
- System built-in (
is_builtin: true) → read-only, must copy to edit - Each Recipe has status badges on the right (bound/default/uploaded)
Main editing area:
- Recipe Editor (
RecipeGraphEditor.vue): Visual state_graph editing - Utils tab (
UtilsTab.vue): user_code / knowledge / skill_templates / external_kb / schemas / assets - Custom UI tab (
CustomUITab.vue): .vue renderer source code - Recipe Author Chat (
RecipeAuthorChat.vue): Vibe-coding side chat (agent -1) - Capability Approval Panel: Capabilities approval panel
5.4 Relationship Between Recipe and Agent
- Recipe bound to agent → agent's subsequent dialogues follow the recipe's state_graph configuration
- One agent can only be bound to one recipe
- One recipe can be bound to multiple agents
- Skills with
scope='recipe'are automatically shared to all agents under the same recipe
5.5 Built-in Recipes
- Location:
src/recipes/_builtin/<id>/ install_built_ins()syncs toworkspace/agent_recipes/at bridge startupis_builtin: true→ UI is read-only (save/delete forbidden), must copy to edit- UI splits into System / My lists
6. Creative Workshop (Flow)
Components: FlowTemplateEditor.vue + FlowTemplateList.vue (inside CreativeWorkshop)
Backend API: src/bridge/routes/flow_templates.py
6.1 Flow Template API
| Endpoint | Description |
|---|---|
GET /api/flow-templates | List (summary rows) |
POST /api/flow-templates | Create |
GET /api/flow-templates/<id> | Get full body |
PUT /api/flow-templates/<id> | Save (validate + persist) |
DELETE /api/flow-templates/<id> | Delete (refused if instances exist) |
POST /api/flow-templates/<id>/validate | Dry-run validation |
POST /api/flow-templates/<id>/duplicate | Clone |
GET /api/flow-templates/<id>/export | Download .flow.json |
POST /api/flow-templates/import | Upload .flow.json |
POST /api/flow-templates/preview_bundle | Pre-check .flow.zip bundle |
POST /api/flow-templates/import_bundle | Import .flow.zip |
GET /api/flow-templates/<id>/export_bundle | Download .flow.zip |
6.2 Flow Bundle Structure (V2 track layout, schema_version=3)
my_flow.flow.zip
├── manifest.json Metadata
├── template.json V1 pool layer (nodes + connections)
├── layout.json V2 track/module/variable layer
├── contract.md Collaboration contract (optional)
├── README.md Description (optional)
├── schemas/ Data schemas (optional)
├── docs/ Documentation (optional)
│ ├── DESIGN.md Design document
│ └── DEVELOPMENT.md Development document
└── renderers/ Custom field renderers (optional)
└── *.vue6.3 Per-flow Docs
Each flow has a docs/ directory, managed via the following endpoints:
GET /api/flow-templates/<id>/docs→ list all documentsGET /api/flow-templates/<id>/docs/<name>→ read document contentPUT /api/flow-templates/<id>/docs/<name>→ write document
DESIGN.md is the flow's design document. DEVELOPMENT always resolves to the global FLOW_DEVELOPMENT.md framework document (is_global: true, prompts before editing).
6.4 Custom Field Renderers
renderers/*.vue are Vue SFCs, compiled and mounted to the flow instance's field editing UI. Used for visual editing of custom field types.
7. Recipe Compile / Dry-run / E2E Test
Entry: Buttons inside CreativeWorkshop editor
7.1 Compile
POST /api/recipes/<id>/compile
- Validates state_graph topology completeness
- Checks all node references are valid
- Validates edge condition expressions pass AST whitelist
- Checks tools in tool_whitelist exist
- Returns
{ok, errors, warnings}
7.2 Dry-run
POST /api/recipes/<id>/dryrun
- Uses stub asker + mock LLM to run full state_graph
- Validates all units can execute
- Does not consume real LLM tokens
- Returns
{ok, outcome, trace}
7.3 E2E End-to-end Test
POST /api/recipes/<id>/e2e-test
- Creates temporary agent → binds recipe → sends test message → validates full chain
- Uses real LLM calls
- Check bridge log's
session.contact.end/e2e_test done pass=to determine pass/fail - Returns
{ok, pass, details}
Developer Perspective
Want to build an ecosystem in the workshop?
- Recipe: Modify
workspace/agent_recipes/<id>/→ import/export → community sharing - Flow:
workspace/manager/flows/<id>/→ template.json + layout.json + renderers/ - Broker: See Pipeline & Flow Manual
