command-sub-agent
專責處理 CBF (Commanded Behavior Frame) 類型的需求。讀取規格目錄結構,生成/審查 Command Side 設計與實作。支援 Java、TypeScript、Go 多語言。
Best use case
command-sub-agent is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
專責處理 CBF (Commanded Behavior Frame) 類型的需求。讀取規格目錄結構,生成/審查 Command Side 設計與實作。支援 Java、TypeScript、Go 多語言。
Teams using command-sub-agent should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/command-sub-agent/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How command-sub-agent Compares
| Feature / Agent | command-sub-agent | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
專責處理 CBF (Commanded Behavior Frame) 類型的需求。讀取規格目錄結構,生成/審查 Command Side 設計與實作。支援 Java、TypeScript、Go 多語言。
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Command Sub-agent Skill
## 觸發時機
- analyze-frame 判定 frame_type=CommandedBehaviorFrame 時
- 需要建立/修改 Command Side (寫模型) 的用例、聚合、事件時
- saga-orchestrator 分派 Command 類型任務時
## 核心任務
1. 讀取規格目錄結構(frame.yaml, machine/, controlled-domain/)
2. 設計/驗證 CQRS Command Side 的用例、聚合與事件流
3. 產出程式碼骨架或審查既有實作
4. 確保 Frame Concerns 都有對應的實作
---
## 規格目錄讀取
本 Skill 讀取以下規格檔案:
```
docs/specs/{feature-name}/
├── frame.yaml # 讀取 frame_concerns, cross_context_dependencies
├── requirements/ # 讀取業務規則
│ └── req-{n}-{feature}.yaml
├── machine/ # 讀取 Application 層規格
│ ├── controller.yaml
│ └── use-case.yaml
├── controlled-domain/ # 讀取 Domain 層規格
│ └── aggregate.yaml
└── cross-context/ # 讀取跨 BC 依賴
└── {context}.yaml
```
---
## Claude Code Sub-agent 整合
本 Skill 可作為 `runSubagent` 的任務目標:
```
saga-orchestrator → runSubagent → command-sub-agent
├── 讀取規格目錄
├── 套用 coding-standards
├── 套用 enforce-contract
└── 輸出 Command Side 代碼
```
### 被分派時的輸入格式
```yaml
task:
type: "command"
spec_dir: "docs/specs/create-workflow/"
language: "typescript" # | java | go
output_paths:
application: "src/application/use-cases/"
domain: "src/domain/"
```
---
## 工作流程
### 1. 解析規格
```yaml
# 從 frame.yaml 讀取
problem_frame: "CreateWorkflow"
frame_type: CommandedBehaviorFrame
# 識別 Frame Concerns 需要滿足
frame_concerns:
- FC1: Structure Integrity → 對應 aggregate.yaml#invariants
- FC2: Concurrency → 對應 use-case.yaml#transaction_boundary
# 識別跨 BC 依賴
cross_context_dependencies:
- XC1: Authorization → 需整合 ACL
```
### 2. 生成 Use Case
從 `machine/use-case.yaml` 生成 Application 層代碼:
- 讀取 Input/Output 定義
- 讀取 contracts (pre/post-conditions)
- 讀取 transaction_boundary, idempotency 設定
- 讀取 publishes_events 列表
### 3. 生成 Aggregate
從 `controlled-domain/aggregate.yaml` 生成 Domain 層代碼:
- 讀取 identity, properties
- 讀取 entities, value_objects
- 讀取 invariants(在 constructor 和 mutating methods 中強制執行)
- 讀取 domain_events
### 4. 整合 Cross-Context
從 `cross-context/{context}.yaml` 整合 ACL:
- 在 Use Case 中注入 ACL 介面
- 在執行前進行授權檢查
---
## TypeScript 生成範例
### Use Case (從 machine/use-case.yaml 生成)
```typescript
// src/application/use-cases/CreateWorkflowUseCase.ts
// Generated from: docs/specs/create-workflow/machine/use-case.yaml
import { AuthorizationService } from '@/domain/services/AuthorizationService';
import { WorkflowRepository } from '@/domain/repositories/WorkflowRepository';
import { EventPublisher } from '@/domain/events/EventPublisher';
import { Workflow } from '@/domain/aggregates/Workflow';
import { WorkflowCreatedEvent } from '@/domain/events/WorkflowCreatedEvent';
// ===== Input/Output (from use-case.yaml#input/output) =====
export interface CreateWorkflowInput {
readonly boardId: string;
readonly name: string;
readonly operatorId: string;
}
export interface CreateWorkflowOutput {
readonly workflowId: string;
readonly status: WorkflowStatus;
readonly createdAt: Date;
}
// ===== Use Case =====
export class CreateWorkflowUseCase {
constructor(
// XC1: Authorization dependency (from cross-context/authorization.yaml)
private readonly authorizationService: AuthorizationService,
private readonly workflowRepository: WorkflowRepository,
private readonly eventPublisher: EventPublisher,
) {}
async execute(input: CreateWorkflowInput): Promise<CreateWorkflowOutput> {
// ===== Pre-conditions (from use-case.yaml#contracts.pre_conditions) =====
if (!input.boardId) {
throw new ValidationError('boardId is required');
}
if (!input.name) {
throw new ValidationError('name is required');
}
if (!input.operatorId) {
throw new ValidationError('operatorId is required');
}
// ===== XC1: Authorization Check (from cross-context/authorization.yaml) =====
const authResult = await this.authorizationService.canExecute(
input.operatorId,
'create',
'Workflow',
input.boardId,
);
if (!authResult.authorized) {
throw new UnauthorizedError(`Not authorized: ${authResult.reason}`);
}
// ===== Domain Logic (from controlled-domain/aggregate.yaml) =====
const workflow = Workflow.create({
boardId: new BoardId(input.boardId),
name: new WorkflowName(input.name),
createdBy: new UserId(input.operatorId),
});
// ===== Persist =====
await this.workflowRepository.save(workflow);
// ===== Publish Domain Event (from use-case.yaml#publishes_events) =====
await this.eventPublisher.publish(new WorkflowCreatedEvent({
workflowId: workflow.id.value,
boardId: workflow.boardId.value,
name: workflow.name.value,
createdBy: workflow.createdBy.value,
createdAt: workflow.createdAt,
}));
// ===== Post-conditions (from use-case.yaml#contracts.post_conditions) =====
// POST1: result.workflowId is not null - enforced by return type
return {
workflowId: workflow.id.value,
status: workflow.status,
createdAt: workflow.createdAt,
};
}
}
```
### Aggregate (從 controlled-domain/aggregate.yaml 生成)
```typescript
// src/domain/aggregates/Workflow.ts
// Generated from: docs/specs/create-workflow/controlled-domain/aggregate.yaml
import { WorkflowId } from '../value-objects/WorkflowId';
import { WorkflowName } from '../value-objects/WorkflowName';
import { BoardId } from '../value-objects/BoardId';
import { Stage } from '../entities/Stage';
export class Workflow {
// ===== Identity (from aggregate.yaml#identity) =====
readonly id: WorkflowId;
// ===== Properties (from aggregate.yaml#properties) =====
readonly boardId: BoardId;
private _name: WorkflowName;
private _stages: Stage[] = [];
readonly createdBy: UserId;
readonly createdAt: Date;
private constructor(props: WorkflowProps) {
this.id = props.id;
this.boardId = props.boardId;
this._name = props.name;
this.createdBy = props.createdBy;
this.createdAt = props.createdAt;
// ===== INV1: Enforce invariants in constructor (from aggregate.yaml#invariants) =====
this.validateInvariants();
}
static create(props: CreateWorkflowProps): Workflow {
return new Workflow({
id: WorkflowId.generate(),
boardId: props.boardId,
name: props.name,
createdBy: props.createdBy,
createdAt: new Date(),
});
}
// ===== Mutating Methods =====
addStage(stage: Stage): void {
// ===== FC1: Structure Integrity - Lane Hierarchy (from frame_concerns) =====
// Stage may be root or nested, validated in Stage entity
this._stages.push(stage);
// Re-validate invariants after mutation
this.validateInvariants();
}
// ===== Invariants Validation (from aggregate.yaml#invariants.shared) =====
private validateInvariants(): void {
// INV1: Structure Integrity
for (const stage of this._stages) {
for (const lane of stage.swimLanes) {
// SwimLane cannot exist at root; it must be under a Stage
if (!lane.parentStage) {
throw new InvariantViolationError(
'SwimLane must be under a Stage'
);
}
}
}
}
// ===== Getters =====
get name(): WorkflowName {
return this._name;
}
get stages(): readonly Stage[] {
return [...this._stages];
}
get status(): WorkflowStatus {
return this._stages.length > 0
? WorkflowStatus.Active
: WorkflowStatus.Empty;
}
}
```
---
## Go 生成範例
### Use Case
```go
// src/application/usecase/create_workflow.go
// Generated from: docs/specs/create-workflow/machine/use-case.yaml
package usecase
import (
"context"
"time"
"myapp/domain/aggregates"
"myapp/domain/events"
"myapp/domain/services"
"myapp/domain/valueobjects"
)
// ===== Input/Output (from use-case.yaml) =====
type CreateWorkflowInput struct {
BoardID string `json:"board_id" validate:"required,uuid"`
Name string `json:"name" validate:"required,min=1,max=100"`
OperatorID string `json:"operator_id" validate:"required,uuid"`
}
type CreateWorkflowOutput struct {
WorkflowID string `json:"workflow_id"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
// ===== Use Case =====
type CreateWorkflowUseCase struct {
authService services.AuthorizationService // XC1
workflowRepo aggregates.WorkflowRepository
eventPub events.EventPublisher
}
func NewCreateWorkflowUseCase(
authService services.AuthorizationService,
workflowRepo aggregates.WorkflowRepository,
eventPub events.EventPublisher,
) *CreateWorkflowUseCase {
return &CreateWorkflowUseCase{
authService: authService,
workflowRepo: workflowRepo,
eventPub: eventPub,
}
}
func (uc *CreateWorkflowUseCase) Execute(
ctx context.Context,
input CreateWorkflowInput,
) (*CreateWorkflowOutput, error) {
// ===== Pre-conditions (from use-case.yaml#contracts.pre_conditions) =====
if err := ValidateInput(input); err != nil {
return nil, err
}
// ===== XC1: Authorization Check =====
authResult, err := uc.authService.CanExecute(
ctx,
input.OperatorID,
services.ActionCreate,
services.ResourceWorkflow,
input.BoardID,
)
if err != nil {
return nil, err
}
if !authResult.Authorized {
return nil, domain.NewUnauthorizedError(authResult.Reason)
}
// ===== Domain Logic =====
workflow, err := aggregates.NewWorkflow(
valueobjects.NewBoardID(input.BoardID),
valueobjects.NewWorkflowName(input.Name),
valueobjects.NewUserID(input.OperatorID),
)
if err != nil {
return nil, err
}
// ===== Persist =====
if err := uc.workflowRepo.Save(ctx, workflow); err != nil {
return nil, err
}
// ===== Publish Domain Event =====
if err := uc.eventPub.Publish(ctx, events.NewWorkflowCreatedEvent(workflow)); err != nil {
return nil, err
}
return &CreateWorkflowOutput{
WorkflowID: workflow.ID().String(),
Status: string(workflow.Status()),
CreatedAt: workflow.CreatedAt(),
}, nil
}
```
### Aggregate
```go
// src/domain/aggregates/workflow.go
// Generated from: docs/specs/create-workflow/controlled-domain/aggregate.yaml
package aggregates
import (
"time"
"myapp/domain/entities"
"myapp/domain/valueobjects"
)
type Workflow struct {
id valueobjects.WorkflowID
boardID valueobjects.BoardID
name valueobjects.WorkflowName
stages []*entities.Stage
createdBy valueobjects.UserID
createdAt time.Time
}
func NewWorkflow(
boardID valueobjects.BoardID,
name valueobjects.WorkflowName,
createdBy valueobjects.UserID,
) (*Workflow, error) {
w := &Workflow{
id: valueobjects.GenerateWorkflowID(),
boardID: boardID,
name: name,
stages: make([]*entities.Stage, 0),
createdBy: createdBy,
createdAt: time.Now(),
}
// ===== INV1: Validate invariants in constructor =====
if err := w.validateInvariants(); err != nil {
return nil, err
}
return w, nil
}
func (w *Workflow) AddStage(stage *entities.Stage) error {
// ===== FC1: Structure Integrity =====
w.stages = append(w.stages, stage)
// Re-validate after mutation
return w.validateInvariants()
}
// ===== Invariants (from aggregate.yaml#invariants.shared) =====
func (w *Workflow) validateInvariants() error {
// INV1: Structure Integrity - Lane hierarchy
for _, stage := range w.stages {
for _, lane := range stage.SwimLanes() {
if lane.ParentStage() == nil {
return domain.NewInvariantViolationError(
"SwimLane must be under a Stage",
)
}
}
}
return nil
}
// ===== Getters =====
func (w *Workflow) ID() valueobjects.WorkflowID { return w.id }
func (w *Workflow) BoardID() valueobjects.BoardID { return w.boardID }
func (w *Workflow) Name() valueobjects.WorkflowName { return w.name }
func (w *Workflow) Stages() []*entities.Stage { return w.stages }
func (w *Workflow) CreatedBy() valueobjects.UserID { return w.createdBy }
func (w *Workflow) CreatedAt() time.Time { return w.createdAt }
func (w *Workflow) Status() WorkflowStatus {
if len(w.stages) > 0 {
return WorkflowStatusActive
}
return WorkflowStatusEmpty
}
```
---
## Frame Concerns 對應表
生成代碼時,確保每個 Frame Concern 都有對應的實作:
| Frame Concern | 規格位置 | 實作位置 |
|---------------|----------|----------|
| FC1: Structure Integrity | aggregate.yaml#invariants.shared | Aggregate.validateInvariants() |
| FC2: Concurrency | use-case.yaml#transaction_boundary | Use Case transaction handling |
| XC1: Authorization | cross-context/authorization.yaml | Use Case authorization check |
---
## 品質檢查清單
- [ ] 是否讀取完整的規格目錄結構?
- [ ] 是否使用 Input/Output 模式並保持不可變?
- [ ] 每個 Frame Concern 是否都有對應實作?
- [ ] 跨 BC 依賴是否透過 ACL 整合?
- [ ] pre-conditions 是否完整覆蓋?
- [ ] Aggregate invariants 是否在 constructor 和 mutating methods 中強制執行?
- [ ] Domain Events 是否正確發布?
- [ ] Repository 介面是否位於 Domain,實作位於 Infrastructure?
---
## 常見錯誤防範
- ❌ 忽略 Frame Concerns,生成「剛好能跑」但不滿足業務規則的代碼
- ❌ 在 Domain/UseCase 中使用框架註解
- ❌ 跳過 ACL,直接呼叫外部 BC
- ❌ 在 Use Case 中混入查詢邏輯(應留給 query-sub-agent)
- ❌ 使用可變的 Input/Output 物件
- ❌ 忘記在 mutating methods 後驗證 invariantsRelated Skills
kitt-create-slash-commands
Expert guidance for creating slash commands. Use when working with slash commands, creating custom commands, understanding command structure, or learning YAML configuration.
command-to-subagent
Use when converting a Ruly command to use subagent execution, when a command has heavy MCP/API logic that should be isolated, or when asked to "make this a subagent"
Command Development
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
agent-command-authoring
Create Claude Code slash commands and OpenCode command files that delegate to subagents. Use when creating new commands or refactoring existing ones to follow the delegation pattern.
running-interactive-commands-with-tmux
Controls interactive CLI tools (vim, git rebase -i, REPLs) through tmux detached sessions and send-keys. Use when running tools requiring terminal interaction, programmatic editor control, or orchestrating Claude Code sessions. Triggers include "interactive command", "vim", "REPL", "tmux", or "git rebase -i".
ln-751-command-templates
Generates individual .claude/commands files from templates
claude-command-authoring
Creates custom slash commands for Claude Code with proper syntax, frontmatter, arguments, bash execution, and file references. Use when building slash commands, creating custom Claude Code commands, setting up team workflows, or when users mention slash commands, command files, or .md command creation.
agent-friendly-commands
Use these when you want low-noise lint/test output (good for LLM/CI logs) while staying aligned with repo policy.
bgo
Automates the complete Blender build-go workflow, from building and packaging your extension/add-on to removing old versions, installing, enabling, and launching Blender for quick testing and iteration.
mcp-create-declarative-agent
Skill converted from mcp-create-declarative-agent.prompt.md
MCP Architecture Expert
Design and implement Model Context Protocol servers for standardized AI-to-data integration with resources, tools, prompts, and security best practices
mathem-shopping
Automatiserar att logga in på Mathem.se, söka och lägga till varor från en lista eller recept, hantera ersättningar enligt policy och reservera leveranstid, men lämnar varukorgen redo för manuell checkout.