skill-system-tkt

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill System TKT

Skill System TKT

Single source of truth for all ticket operations across the skill system.
Skill系统中所有工单操作的唯一可信源。

Two Backends, One Lifecycle

两种后端,统一生命周期

Backend 1: Filesystem Bundles (tkt.sh)
  Project-level work management.
  Roadmap → Bundle → Tickets (YAML files in .tkt/)
  Use for: PM-driven decomposition, multi-agent bundles, review generation.

Backend 2: DB Durable Tickets (tickets.py)
  Session-level lifecycle management.
  Intake → Claim → Work → Block/Close (Postgres agent_memories)
  Use for: claim arbitration, session loops, scope enforcement, refresh.
Both backends share the same conceptual lifecycle:
OPEN → CLAIMED → IN_PROGRESS → DONE/BLOCKED/FAILED/CLOSED
Backend 1: Filesystem Bundles (tkt.sh)
  项目级工作管理。
  路线图 → 包 → 工单(.tkt/目录下的YAML文件)
  适用场景:PM Agent驱动的任务拆解、多Agent包、评审生成。

Backend 2: DB Durable Tickets (tickets.py)
  会话级生命周期管理。
  接收 → 认领 → 工作 → 阻塞/关闭(存储于Postgres的agent_memories)
  适用场景:认领仲裁、会话循环、范围管控、刷新。
两种后端共享相同的概念化生命周期:
OPEN → CLAIMED → IN_PROGRESS → DONE/BLOCKED/FAILED/CLOSED

Core Concepts

核心概念

Roadmap (project-level, maintained by PM Agent)
 └─ TKT Bundle (a unit of deliverable work)
     ├─ TKT-000  Integrate   (claimed by Main Agent — coordinates bundle)
     ├─ TKT-001  Worker      (claimed by any agent — actual work)
     ├─ TKT-002  Worker      (claimed by any agent — actual work)
     ├─ TKT-...  Worker      (can be added mid-flight)
     └─ TKT-A00  Audit       (spot-check ticket — random quality verification)
Roadmap (项目级,由PM Agent维护)
 └─ TKT Bundle (可交付工作单元)
     ├─ TKT-000  Integrate   (由Main Agent认领 —— 协调包内工作)
     ├─ TKT-001  Worker      (由任意Agent认领 —— 执行实际工作)
     ├─ TKT-002  Worker      (由任意Agent认领 —— 执行实际工作)
     ├─ TKT-...  Worker      (可在任务进行中添加)
     └─ TKT-A00  Audit       (抽查工单 —— 随机质量验证)

Roles

角色

RoleWhoResponsibility
PM AgentPlan/Review agentInterprets user intent → maintains roadmap → creates bundles → reviews results
Main AgentAgent that claims TKT-000Coordinates the bundle, integrates outputs, closes TKT-000 when all work is done
Worker AgentAny agent that claims a worker TKTExecutes the ticket's task, reports result
Audit AgentAgent that claims TKT-A00Randomly spot-checks engineering quality across the project
角色负责Agent职责
PM Agent规划/评审Agent解读用户意图 → 维护路线图 → 创建包 → 评审结果
Main Agent认领TKT-000的Agent协调包内工作,整合输出,当所有工作完成后关闭TKT-000
Worker Agent认领Worker工单的任意Agent执行工单任务,上报结果
Audit Agent认领TKT-A00的Agent随机抽查项目的工程质量

Ticket States

工单状态

OPEN → CLAIMED → IN_PROGRESS → DONE
                              → BLOCKED (needs new TKT or intervention)
                              → FAILED  (requires retry or escalation)
OPEN → CLAIMED → IN_PROGRESS → DONE
                              → BLOCKED(需要新工单或人工介入)
                              → FAILED(需要重试或升级处理)

Bundle Lifecycle

包生命周期

mermaid
flowchart TD
    A[PM Agent: interpret user intent] --> B[Create TKT Bundle]
    B --> C[Agents claim tickets]
    C --> D{All worker TKTs DONE?}
    D -->|No| E[Continue / spawn new TKTs]
    E --> C
    D -->|Yes| F[Audit Agent: spot-check]
    F --> G[Main Agent: close TKT-000]
    G --> H[PM Agent: generate Review Bundle]
    H --> I[Review Agent + User discussion]
mermaid
flowchart TD
    A[PM Agent: interpret user intent] --> B[Create TKT Bundle]
    B --> C[Agents claim tickets]
    C --> D{All worker TKTs DONE?}
    D -->|No| E[Continue / spawn new TKTs]
    E --> C
    D -->|Yes| F[Audit Agent: spot-check]
    F --> G[Main Agent: close TKT-000]
    G --> H[PM Agent: generate Review Bundle]
    H --> I[Review Agent + User discussion]

Configuration

配置

All runtime settings are in
config/tkt.yaml
. Config is the single source of truth — values in this document are documentation only.
See:
../../config/tkt.yaml
所有运行时设置均在
config/tkt.yaml
中。配置文件是唯一可信源——本文档中的值仅作参考。
查看:
../../config/tkt.yaml

Data Model

数据模型

Filesystem Backend (.tkt/)

文件系统后端(.tkt/)

.tkt/
├── roadmap.yaml              # Project-level roadmap
├── bundles/
│   ├── B-001/
│   │   ├── bundle.yaml       # Bundle metadata
│   │   ├── TKT-000.yaml     # Integrate ticket
│   │   ├── TKT-001.yaml     # Worker ticket
│   │   ├── TKT-A00.yaml     # Audit ticket
│   │   └── review.yaml      # Generated after bundle closes
│   └── B-002/
│       └── ...
└── history.log               # Append-only event log
.tkt/
├── roadmap.yaml              # 项目级路线图
├── bundles/
│   ├── B-001/
│   │   ├── bundle.yaml       # 包元数据
│   │   ├── TKT-000.yaml     # Integrator工单
│   │   ├── TKT-001.yaml     # Worker工单
│   │   ├── TKT-A00.yaml     # Audit工单
│   │   └── review.yaml      # 包关闭后生成
│   └── B-002/
│       └── ...
└── history.log               # 追加式事件日志

DB Backend (agent_memories)

数据库后端(agent_memories)

Durable tickets stored via
agent_memories
with metadata fields:
  • ticket_id
    ,
    title
    ,
    summary
    ,
    status
  • claimed_by_session
    ,
    claimed_at
    ,
    closed_at
  • batch_id
    ,
    queue_order
    ,
    ticket_type
    (WORKER/INTEGRATOR)
  • task_provenance
    (workflow/verification/legacy)
持久化工单通过
agent_memories
存储,包含以下元数据字段:
  • ticket_id
    ,
    title
    ,
    summary
    ,
    status
  • claimed_by_session
    ,
    claimed_at
    ,
    closed_at
  • batch_id
    ,
    queue_order
    ,
    ticket_type
    (WORKER/INTEGRATOR)
  • task_provenance
    (workflow/verification/legacy)

Operations

操作指南

Filesystem Bundle Operations (tkt.sh)

文件系统包操作(tkt.sh)

init-roadmap

init-roadmap

Initialize the
.tkt/
directory and
roadmap.yaml
for a project.
bash
bash "<this-skill-dir>/scripts/tkt.sh" init-roadmap --project "<name>"
初始化项目的
.tkt/
目录和
roadmap.yaml
文件。
bash
bash "<this-skill-dir>/scripts/tkt.sh" init-roadmap --project "<name>"

create-bundle

create-bundle

PM Agent interprets user intent and creates a new TKT bundle with tickets.
bash
bash "<this-skill-dir>/scripts/tkt.sh" create-bundle --goal "<goal>" [--track "<name>"] [--source-plan "<file>"] [--worktree] [--carryover B-001]
  • --track
    : optional workstream label persisted to
    bundle.yaml
    (
    track
    field)
  • --source-plan
    : optional source plan path persisted to
    bundle.yaml
    (
    source_plan
    field)
  • --worktree
    : create
    .worktrees/B-NNN
    and persist
    worktree_path
    /
    worktree_branch
  • --carryover
    : import worker tickets from another bundle's
    carryover.yaml
Procedure:
scripts/create-bundle.md
PM Agent解读用户意图,创建包含工单的新TKT包。
bash
bash "<this-skill-dir>/scripts/tkt.sh" create-bundle --goal "<goal>" [--track "<name>"] [--source-plan "<file>"] [--worktree] [--carryover B-001]
  • --track
    : 可选的工作流标签,将持久化到
    bundle.yaml
    track
    字段
  • --source-plan
    : 可选的源计划路径,将持久化到
    bundle.yaml
    source_plan
    字段
  • --worktree
    : 创建
    .worktrees/B-NNN
    并持久化
    worktree_path
    /
    worktree_branch
  • --carryover
    : 从其他包的
    carryover.yaml
    中导入Worker工单
操作流程:
scripts/create-bundle.md

claim-ticket
(filesystem)

claim-ticket
(文件系统)

bash
bash "<this-skill-dir>/scripts/tkt.sh" claim --bundle B-001 --ticket TKT-001 --agent "<agent-id>"
bash
bash "<this-skill-dir>/scripts/tkt.sh" claim --bundle B-001 --ticket TKT-001 --agent "<agent-id>"

update-ticket

update-ticket

bash
bash "<this-skill-dir>/scripts/tkt.sh" update --bundle B-001 --ticket TKT-001 --status done --summary "<result>" --evidence "<proof>"
bash "<this-skill-dir>/scripts/tkt.sh" update --bundle B-001 --ticket TKT-001 --status blocked --reason "<why blocked>"
  • --evidence
    /
    --evidence-file
    : required when
    --status done
    ; persisted to
    result.evidence
  • --reason
    : required when
    --status blocked
    ; persisted to
    result.notes
  • valid transitions are enforced;
    claim
    handles
    open|blocked -> claimed
  • every status change appends
    transition_log[]
    with
    from
    ,
    to
    ,
    timestamp
    , and
    agent
bash
bash "<this-skill-dir>/scripts/tkt.sh" update --bundle B-001 --ticket TKT-001 --status done --summary "<result>" --evidence "<proof>"
bash "<this-skill-dir>/scripts/tkt.sh" update --bundle B-001 --ticket TKT-001 --status blocked --reason "<why blocked>"
  • --evidence
    /
    --evidence-file
    : 当
    --status done
    时为必填项;将持久化到
    result.evidence
  • --reason
    : 当
    --status blocked
    时为必填项;将持久化到
    result.notes
  • 仅允许合法的状态转换;
    claim
    命令处理
    open|blocked -> claimed
    转换
  • 每次状态变更都会在
    transition_log[]
    中追加
    from
    to
    timestamp
    agent
    信息

add-ticket

add-ticket

bash
bash "<this-skill-dir>/scripts/tkt.sh" add --bundle B-001 --type worker --title "<title>" --description "<desc>" [--skills "skill-a,skill-b"] [--wave 2] [--qa-scenarios "run pytest,inspect output"]
  • --skills
    : optional comma-separated skill names stored as YAML list metadata
  • --wave
    : optional numeric wave value for execution ordering metadata
  • --qa-scenarios
    : optional comma-separated QA checklist stored as YAML list metadata
bash
bash "<this-skill-dir>/scripts/tkt.sh" add --bundle B-001 --type worker --title "<title>" --description "<desc>" [--skills "skill-a,skill-b"] [--wave 2] [--qa-scenarios "run pytest,inspect output"]
  • --skills
    : 可选的逗号分隔技能名称,将存储为YAML列表元数据
  • --wave
    : 可选的数值型wave值,用于执行顺序元数据
  • --qa-scenarios
    : 可选的逗号分隔QA检查项,将存储为YAML列表元数据

bundle-status

bundle-status

bash
bash "<this-skill-dir>/scripts/tkt.sh" status --bundle B-001
  • includes each ticket's
    transition_log
    history in the JSON payload
bash
bash "<this-skill-dir>/scripts/tkt.sh" status --bundle B-001
  • JSON返回结果中包含每个工单的
    transition_log
    历史

close-bundle

close-bundle

bash
bash "<this-skill-dir>/scripts/tkt.sh" close --bundle B-001 [--merge] [--no-memory]
Close-time gates:
  • structural validation via
    python3 spec/validate_repo_structural.py
  • optional
    config/tkt.yaml
    close_gate.command
  • executable acceptance criteria (
    {type: command, ...}
    objects)
  • audit ticket must be claimed and
    done
  • audit claimant must differ from any worker claimant
  • worktree-backed bundles must be clean before close
Close-time artifacts:
  • review.yaml
    auto-fills
    evidence_summary
    and
    acceptance_results
  • review.yaml
    also includes
    transition_stats
    derived from
    transition_log
  • done worker/audit tickets auto-store learnings to memory through
    mem.py store
    unless
    --no-memory
    is used
  • close JSON includes
    next_steps_hint
    for the startup review cycle
  • failed executable acceptance criteria generate
    carryover.yaml
  • --merge
    merges
    worktree_branch
    into the current branch and removes the worktree after a successful close
bash
bash "<this-skill-dir>/scripts/tkt.sh" close --bundle B-001 [--merge] [--no-memory]
关闭时的校验规则:
  • 通过
    python3 spec/validate_repo_structural.py
    进行结构验证
  • 可选的
    config/tkt.yaml
    中的
    close_gate.command
  • 可执行的验收标准(
    {type: command, ...}
    对象)
  • Audit工单必须已被认领且状态为
    done
  • Audit工单的认领者必须与所有Worker工单的认领者不同
  • 基于工作树的包在关闭前必须处于干净状态
关闭时生成的产物:
  • review.yaml
    自动填充
    evidence_summary
    acceptance_results
  • review.yaml
    还包含从
    transition_log
    导出的
    transition_stats
  • 已完成的Worker/Audit工单会自动通过
    mem.py store
    将经验存储到内存,除非使用
    --no-memory
    参数
  • 关闭时的JSON返回结果包含启动评审周期的
    next_steps_hint
  • 验收标准执行失败时会生成
    carryover.yaml
  • --merge
    参数会将
    worktree_branch
    合并到当前分支,并在关闭成功后删除工作树

express

express

bash
bash "<this-skill-dir>/scripts/tkt.sh" express close EXP-001 --evidence "<proof>"
  • express close
    requires
    --evidence
    or
    --evidence-file
  • files_changed > 3
    upgrades the express ticket into a bundle worker ticket while preserving evidence
bash
bash "<this-skill-dir>/scripts/tkt.sh" express close EXP-001 --evidence "<proof>"
  • express close
    需要
    --evidence
    --evidence-file
    参数
  • files_changed > 3
    时,快速工单会升级为包内Worker工单,并保留证据

list-bundles

list-bundles

bash
bash "<this-skill-dir>/scripts/tkt.sh" list
bash
bash "<this-skill-dir>/scripts/tkt.sh" list

roadmap-transition

roadmap-transition

Transition roadmap to a new stage with gate checks.
bash
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-transition --stage active --reason "bundles created"
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-transition --stage done --reason "all goals met" [--force]
Gate checks:
  • planning → active
    : At least one bundle must exist
  • * → done
    : All bundles must be closed/archived
  • roadmap
    decision_gates
    for the target stage must be passed unless
    --force
  • Invalid transitions are rejected unless
    --force
    is used
通过校验规则将路线图转换到新阶段。
bash
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-transition --stage active --reason "bundles created"
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-transition --stage done --reason "all goals met" [--force]
校验规则:
  • planning → active
    : 必须至少存在一个包
  • * → done
    : 所有包必须已关闭/归档
  • 目标阶段的路线图
    decision_gates
    必须通过,除非使用
    --force
    参数
  • 非法转换会被拒绝,除非使用
    --force
    参数

roadmap-status

roadmap-status

Show roadmap stage, bundle summary, and allowed transitions.
bash
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-status
显示路线图阶段、包摘要和允许的转换。
bash
bash "<this-skill-dir>/scripts/tkt.sh" roadmap-status

DB Ticket Lifecycle Operations (tickets.py)

数据库工单生命周期操作(tickets.py)

intake-ticket

intake-ticket

Create or sync a durable workflow ticket from user-facing intake (note/note_tasks.md).
bash
python3 "<this-skill-dir>/scripts/tickets.py" intake-ticket --from-note-tasks
python3 "<this-skill-dir>/scripts/tickets.py" intake-ticket --ticket-id TKT-001 --title "..." --summary "..."
从用户提交的任务(note/note_tasks.md)创建或同步持久化工作流工单。
bash
python3 "<this-skill-dir>/scripts/tickets.py" intake-ticket --from-note-tasks
python3 "<this-skill-dir>/scripts/tickets.py" intake-ticket --ticket-id TKT-001 --title "..." --summary "..."

list-tickets
(DB)

list-tickets
(数据库)

bash
python3 "<this-skill-dir>/scripts/tickets.py" list-tickets [--unresolved-only] [--batch-id BATCH-001]
bash
python3 "<this-skill-dir>/scripts/tickets.py" list-tickets [--unresolved-only] [--batch-id BATCH-001]

claim-ticket
(DB)

claim-ticket
(数据库)

Session-based claiming with conflict-safe advisory locks.
bash
python3 "<this-skill-dir>/scripts/tickets.py" claim-ticket --ticket-id TKT-001 [--session-id ses_xxx]
基于会话的认领,使用冲突安全的 advisory locks。
bash
python3 "<this-skill-dir>/scripts/tickets.py" claim-ticket --ticket-id TKT-001 [--session-id ses_xxx]

block-ticket

block-ticket

bash
python3 "<this-skill-dir>/scripts/tickets.py" block-ticket --ticket-id TKT-001 [--reason "blocker"]
bash
python3 "<this-skill-dir>/scripts/tickets.py" block-ticket --ticket-id TKT-001 [--reason "blocker"]

close-ticket
(DB)

close-ticket
(数据库)

Runs refresh-new-tasks before closing. Refuses integrator closure if new claimable tasks exist.
bash
python3 "<this-skill-dir>/scripts/tickets.py" close-ticket [--ticket-id TKT-001] --session-id ses_xxx
关闭前会运行refresh-new-tasks。如果存在新的可认领任务,Integrator工单无法关闭。
bash
python3 "<this-skill-dir>/scripts/tickets.py" close-ticket [--ticket-id TKT-001] --session-id ses_xxx

check-open-tickets

check-open-tickets

bash
python3 "<this-skill-dir>/scripts/tickets.py" check-open-tickets [--session-id ses_xxx]
bash
python3 "<this-skill-dir>/scripts/tickets.py" check-open-tickets [--session-id ses_xxx]

claim-summary

claim-summary

Report batch/session claim ownership with collaboration policy snapshot.
bash
python3 "<this-skill-dir>/scripts/tickets.py" claim-summary [--session-id ses_xxx] [--batch-id BATCH-001]
报告批次/会话的认领归属及协作策略快照。
bash
python3 "<this-skill-dir>/scripts/tickets.py" claim-summary [--session-id ses_xxx] [--batch-id BATCH-001]

session-loop

session-loop

Run the legal worker loop for one session: refresh → resume/claim → work → next.
bash
python3 "<this-skill-dir>/scripts/tickets.py" session-loop --session-id ses_xxx [--batch-id BATCH-001]
为一个会话运行合法的Worker循环:刷新 → 恢复/认领 → 工作 → 下一个任务。
bash
python3 "<this-skill-dir>/scripts/tickets.py" session-loop --session-id ses_xxx [--batch-id BATCH-001]

refresh-new-tasks

refresh-new-tasks

Re-read
note/note_tasks.md
### New
section and ingest newly added work.
bash
python3 "<this-skill-dir>/scripts/tickets.py" refresh-new-tasks [--batch-id BATCH-001]
重新读取
note/note_tasks.md
### New
部分,导入新增的工作任务。
bash
python3 "<this-skill-dir>/scripts/tickets.py" refresh-new-tasks [--batch-id BATCH-001]

refresh-review-inbox

refresh-review-inbox

Parse the review inbox and ingest inbox-derived tickets.
bash
python3 "<this-skill-dir>/scripts/tickets.py" refresh-review-inbox [--batch-id BATCH-001]
解析评审收件箱,导入从收件箱生成的工单。
bash
python3 "<this-skill-dir>/scripts/tickets.py" refresh-review-inbox [--batch-id BATCH-001]

startup-flow

startup-flow

Report the current startup/claim-loop context from zero to review-agent handoff.
bash
python3 "<this-skill-dir>/scripts/tickets.py" startup-flow [--session-id ses_xxx]
报告从初始状态到Review Agent交接的当前启动/认领循环上下文。
bash
python3 "<this-skill-dir>/scripts/tickets.py" startup-flow [--session-id ses_xxx]

integrator-closure-report

integrator-closure-report

Report whether the integrator ticket can legally close the batch.
bash
python3 "<this-skill-dir>/scripts/tickets.py" integrator-closure-report --session-id ses_xxx
报告Integrator工单是否可以合法关闭批次。
bash
python3 "<this-skill-dir>/scripts/tickets.py" integrator-closure-report --session-id ses_xxx

check-ticket-scope

check-ticket-scope

Report whether the changed-file set stays inside the claimed ticket scope.
bash
python3 "<this-skill-dir>/scripts/tickets.py" check-ticket-scope --ticket-id TKT-001
报告变更文件是否在认领工单的范围内。
bash
python3 "<this-skill-dir>/scripts/tickets.py" check-ticket-scope --ticket-id TKT-001

PM Agent Workflow

PM Agent工作流

  1. Interpret Intent — Parse what the user wants, map to roadmap goals
  2. Create Bundle — Break work into tickets (000 + workers + audit)
  3. Monitor — Track bundle progress, unblock agents
  4. Review — After bundle closes, generate review bundle
  5. Discuss — Present findings to user, gather feedback
  6. Update Roadmap — Reflect completed work and new directions
  1. 解读意图 —— 解析用户需求,映射到路线图目标
  2. 创建包 —— 将工作拆解为工单(000 + 工作工单 + 审计工单)
  3. 监控 —— 跟踪包的进度,为Agent排除障碍
  4. 评审 —— 包关闭后,生成评审包
  5. 讨论 —— 向用户展示结果,收集反馈
  6. 更新路线图 —— 记录已完成工作和新方向

PM Agent Decision Matrix

PM Agent决策矩阵

User SaysPM Action
New feature / task requestCreate new goal + bundle
"What's the status?"Run
bundle-status
or
list-tickets
"I changed my mind about X"Update/close relevant tickets, adjust roadmap
"Review the work"Generate review bundle, present findings
"Add more work to current task"
add-ticket
to active bundle
Vague / ambiguous requestClarify intent before creating tickets
用户需求PM Agent操作
新功能/任务请求创建新目标 + 包
"进度如何?"运行
bundle-status
list-tickets
"我改变了对X的想法"更新/关闭相关工单,调整路线图
"评审工作成果"生成评审包,展示结果
"给当前任务添加更多工作"向活跃包中
add-ticket
模糊/不明确的请求先澄清意图再创建工单

Method Laws

方法规则

  • one_ticket_at_a_time: One session may hold at most one active claimed ticket.
  • keep_picking_open_stale: Before ending the round, if OPEN or STALE worker tickets remain claimable, continue claiming the next one.
  • integrator_only_closure: Only the integrator ticket may declare batch closure; worker tickets may close themselves but never the batch.
  • one_ticket_at_a_time:一个会话最多可持有一个活跃的已认领工单。
  • keep_picking_open_stale:在本轮结束前,若仍有可认领的OPEN或STALE状态工作工单,需继续认领下一个。
  • integrator_only_closure:只有Integrator工单可以宣布批次关闭;工作工单可自行关闭,但不能关闭批次。

Collaboration Policy

协作策略

  • question_tool_first: Prefer the question tool for branch decisions when available. Shape: 2-4 options, one recommended, single choice. Fallback: structured single-choice prompt with the same shape.
  • subagent_scope: Subagents must stay inside the currently claimed ticket scope.
  • cross_ticket_loophole: Forbidden — subagents cannot cross ticket boundaries.
  • question_tool_first:当可用时,优先使用问题工具进行分支决策。形式:2-4个选项,推荐一个,单选。回退方案:结构相同的单选提示。
  • subagent_scope:子Agent必须在当前认领的工单范围内工作。
  • cross_ticket_loophole:禁止——子Agent不能跨工单边界。

Subagent Playbook

子Agent操作手册

Preferred use cases (subagents encouraged):
  • Parallel independent subtasks inside the currently claimed ticket
  • Narrow research or grep work that unblocks a claimed ticket decision
  • Isolated read-only verification slices for a claimed ticket
Non-use cases (do NOT use subagents for):
  • Single cohesive code path in one local module
  • Cross-ticket work or anything that widens scope beyond the claimed ticket
  • Performative delegation when the parent session already has enough context
Reporting contract — every subagent invocation must report:
  • subagent_name
    — identifier
  • purpose
    — why this subagent was spawned
  • ticket_scope
    — which ticket it operates within
  • write_capability_used
    — whether it wrote files
  • why_subagent_was_needed_or_not_needed
    — justification
推荐使用场景(鼓励使用子Agent):
  • 当前认领工单内的并行独立子任务
  • 帮助当前认领工单决策的精准调研或搜索工作
  • 当前认领工单的独立只读验证切片
不推荐使用场景(禁止使用子Agent):
  • 单个本地模块内的连贯代码路径
  • 跨工单工作或任何超出当前认领工单范围的操作
  • 父会话已具备足够上下文时的形式化委托
报告约定——每次子Agent调用必须上报:
  • subagent_name
    —— 标识符
  • purpose
    —— 启动该子Agent的原因
  • ticket_scope
    —— 其操作所在的工单
  • write_capability_used
    —— 是否写入文件
  • why_subagent_was_needed_or_not_needed
    —— 合理性说明

Roadmap Stage Transitions

路线图阶段转换

Valid stages:
planning → active → review → done → archived
FromAllowed ToGate Checks
planningactive, archivedAt least one bundle must exist for
active
activereview, blocked, archived
reviewdone, active, archivedAll bundles must be closed/archived for
done
blockedactive, archived
donearchived
Transitions require
--reason
and are logged in
roadmap.yaml
stage_history. Use
--force
to bypass gate checks (logged but not recommended).
有效阶段:
planning → active → review → done → archived
原阶段允许转换到的阶段校验规则
planningactive, archived转换到
active
时必须至少存在一个包
activereview, blocked, archived
reviewdone, active, archived转换到
done
时所有包必须已关闭/归档
blockedactive, archived
donearchived
转换需要
--reason
参数,并会记录到
roadmap.yaml
stage_history
中。 使用
--force
参数可绕过校验规则(会被记录,但不推荐)。

Concurrency

并发处理

  • Filesystem: Lock file (
    .tkt/bundles/B-NNN/.lock
    )
  • DB: PostgreSQL advisory locks for conflict-safe claiming
  • 文件系统:使用锁文件(
    .tkt/bundles/B-NNN/.lock
  • 数据库:使用PostgreSQL的 advisory locks 实现冲突安全的认领

Integration Notes

集成说明

opencode + OMO

opencode + OMO

  • opencode: Agents execute via opencode runtime, agent-id maps to opencode session
  • OMO: Orchestration layer manages agent lifecycle and ticket claiming
  • Filesystem backend is git-friendly, no DB dependency for basic operation
  • DB backend requires PostgreSQL (via skill-system-memory)
skill
{
  "schema_version": "2.0",
  "id": "skill-system-tkt",
  "version": "2.0.0",
  "capabilities": [
     "tkt-init", "tkt-create-bundle", "tkt-claim", "tkt-update", "tkt-add",
     "tkt-status", "tkt-close", "tkt-review", "tkt-list", "tkt-express",
     "tkt-roadmap-transition", "tkt-roadmap-status",
    "tkt-intake", "tkt-claim-db", "tkt-block", "tkt-close-db",
    "tkt-check-open", "tkt-claim-summary", "tkt-session-loop",
    "tkt-refresh-new", "tkt-refresh-inbox", "tkt-startup-flow",
    "tkt-integrator-closure", "tkt-check-scope",
    "pm-interpret", "pm-roadmap"
  ],
  "effects": ["fs.read", "fs.write", "db.read", "db.write", "proc.exec"],
  "operations": {
    "init-roadmap": {
      "description": "Initialize .tkt/ directory and roadmap.yaml",
      "input": { "project": { "type": "string", "required": true } },
      "output": { "description": "Initialized roadmap path", "fields": { "roadmap_path": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "init-roadmap", "--project", "{project}"]
      }
    },
    "create-bundle": {
      "description": "PM Agent creates a TKT bundle from user intent",
      "input": {
        "goal": { "type": "string", "required": true },
        "context": { "type": "string", "required": false },
        "track": { "type": "string", "required": false },
        "source_plan": { "type": "string", "required": false },
        "worktree": { "type": "boolean", "required": false },
        "carryover": { "type": "string", "required": false }
      },
      "output": { "description": "Bundle ID and ticket list", "fields": { "bundle_id": "string", "tickets": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "create-bundle", "--goal", "{goal}", "--track", "{track}", "--source-plan", "{source_plan}"],
        "agent": "scripts/create-bundle.md"
      }
    },
    "claim": {
      "description": "Claim a filesystem ticket within a bundle.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "ticket": { "type": "string", "required": true },
        "agent": { "type": "string", "required": true }
      },
      "output": { "description": "Claim result", "fields": { "claimed": "boolean", "ticket": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "claim", "--bundle", "{bundle}", "--ticket", "{ticket}", "--agent", "{agent}"]
      }
    },
    "update": {
      "description": "Update a filesystem ticket status and summary.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "ticket": { "type": "string", "required": true },
        "status": { "type": "string", "required": true },
        "summary": { "type": "string", "required": false },
        "evidence": { "type": "string", "required": false },
        "evidence_file": { "type": "string", "required": false },
        "reason": { "type": "string", "required": false }
      },
      "output": { "description": "Update result", "fields": { "ticket_id": "string", "new_status": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "update", "--bundle", "{bundle}", "--ticket", "{ticket}", "--status", "{status}"]
      }
    },
    "add": {
      "description": "Add a filesystem worker ticket with structured metadata.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "title": { "type": "string", "required": true },
        "description": { "type": "string", "required": false },
        "category": { "type": "string", "required": false },
        "effort_estimate": { "type": "string", "required": false },
        "skills": { "type": "string", "required": false },
        "wave": { "type": "number", "required": false },
        "qa_scenarios": { "type": "string", "required": false },
        "depends_on": { "type": "string", "required": false },
        "source_plan": { "type": "string", "required": false },
        "source_ticket_index": { "type": "number", "required": false },
        "acceptance": { "type": "string", "required": false }
      },
      "output": { "description": "Added ticket result", "fields": { "ticket_id": "string", "bundle": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "add", "--bundle", "{bundle}", "--title", "{title}"]
      }
    },
    "express": {
      "description": "Manage express tickets without requiring a bundle.",
      "input": {
        "action": { "type": "string", "required": false },
        "title": { "type": "string", "required": false },
        "acceptance": { "type": "string", "required": false },
        "category": { "type": "string", "required": false },
        "effort_estimate": { "type": "string", "required": false },
        "wave": { "type": "number", "required": false },
        "source_plan": { "type": "string", "required": false },
        "source_ticket_index": { "type": "number", "required": false },
        "ticket_id": { "type": "string", "required": false },
        "agent": { "type": "string", "required": false },
        "files_changed": { "type": "number", "required": false },
        "evidence": { "type": "string", "required": false },
        "evidence_file": { "type": "string", "required": false }
      },
      "output": { "description": "Express ticket result", "fields": { "ticket_id": "string", "status": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "express"]
      }
    },
    "bundle-status": {
      "description": "Show bundle status with all tickets",
      "input": { "bundle": { "type": "string", "required": true } },
      "output": { "description": "Bundle status report", "fields": { "bundle": "object" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "status", "--bundle", "{bundle}"]
      }
    },
    "close-bundle": {
      "description": "Close bundle after worker completion and verification gates.",
      "input": { "bundle": { "type": "string", "required": true }, "merge": { "type": "boolean", "required": false } },
      "output": { "description": "Close result", "fields": { "closed": "boolean", "review_path": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "close", "--bundle", "{bundle}"]
      }
    },
    "list-bundles": {
      "description": "List all bundles and their status",
      "input": {},
      "output": { "description": "Bundle list", "fields": { "bundles": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "list"]
      }
    },
    "roadmap-transition": {
      "description": "Transition roadmap to a new stage with gate checks",
      "input": {
        "stage": { "type": "string", "required": true },
        "reason": { "type": "string", "required": true },
        "force": { "type": "boolean", "required": false }
      },
      "output": { "description": "Transition result", "fields": { "transition": "string", "new_stage": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "roadmap-transition", "--stage", "{stage}", "--reason", "{reason}"]
      }
    },
    "roadmap-status": {
      "description": "Show roadmap stage, bundle summary, and allowed transitions",
      "input": {},
      "output": { "description": "Roadmap status", "fields": { "project": "string", "stage": "string", "allowed_transitions": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "roadmap-status"]
      }
    },
    "generate-review": {
      "description": "Generate review bundle post-closure",
      "input": { "bundle": { "type": "string", "required": true } },
      "output": { "description": "Review bundle", "fields": { "review_path": "string" } },
      "entrypoints": { "agent": "scripts/generate-review.md" }
    },
    "intake-ticket": {
      "description": "Create or sync a durable ticket from note_tasks intake",
      "input": {
        "ticket_id": { "type": "string", "required": false },
        "title": { "type": "string", "required": false },
        "from_note_tasks": { "type": "boolean", "required": false }
      },
      "output": { "description": "Canonical ticket record", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "intake-ticket"]
      }
    },
    "list-tickets": {
      "description": "List durable workflow tickets",
      "input": {
        "unresolved_only": { "type": "boolean", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Ticket list", "fields": { "tickets": "array" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "list-tickets"]
      }
    },
    "claim-ticket": {
      "description": "Claim a ticket for the current session (DB-backed, conflict-safe)",
      "input": {
        "ticket_id": { "type": "string", "required": true },
        "session_id": { "type": "string", "required": true }
      },
      "output": { "description": "Claimed ticket", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "claim-ticket", "--ticket-id", "{ticket_id}", "--session-id", "{session_id}"]
      }
    },
    "block-ticket": {
      "description": "Mark a ticket as blocked",
      "input": {
        "ticket_id": { "type": "string", "required": true },
        "reason": { "type": "string", "required": false }
      },
      "output": { "description": "Blocked ticket", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "block-ticket", "--ticket-id", "{ticket_id}"]
      }
    },
    "close-ticket": {
      "description": "Close the currently claimed ticket (runs refresh first)",
      "input": {
        "session_id": { "type": "string", "required": true },
        "ticket_id": { "type": "string", "required": false },
        "resolution": { "type": "string", "required": false }
      },
      "output": { "description": "Closed ticket + refresh status", "fields": { "ticket": "object", "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "close-ticket", "--session-id", "{session_id}"]
      }
    },
    "check-open-tickets": {
      "description": "Report unresolved tickets",
      "input": { "session_id": { "type": "string", "required": false } },
      "output": { "description": "Open ticket report", "fields": { "report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "check-open-tickets"]
      }
    },
    "claim-summary": {
      "description": "Batch/session claim ownership summary with collaboration policy",
      "input": {
        "session_id": { "type": "string", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Claim summary", "fields": { "claim_summary": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "claim-summary"]
      }
    },
    "session-loop": {
      "description": "Run the legal worker loop for one session",
      "input": {
        "session_id": { "type": "string", "required": true },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Loop state", "fields": { "loop_state": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "session-loop", "--session-id", "{session_id}"]
      }
    },
    "refresh-new-tasks": {
      "description": "Re-read note_tasks ### New and ingest new work",
      "input": {
        "batch_id": { "type": "string", "required": false },
        "trigger_point": { "type": "string", "required": false }
      },
      "output": { "description": "Refresh status", "fields": { "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "refresh-new-tasks"]
      }
    },
    "refresh-review-inbox": {
      "description": "Parse review inbox and ingest inbox-derived tickets",
      "input": {
        "batch_id": { "type": "string", "required": false },
        "trigger_point": { "type": "string", "required": false }
      },
      "output": { "description": "Inbox refresh status", "fields": { "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "refresh-review-inbox"]
      }
    },
    "startup-flow": {
      "description": "Startup/claim-loop context from zero to review handoff",
      "input": {
        "session_id": { "type": "string", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Startup context", "fields": { "startup_context": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "startup-flow"]
      }
    },
    "integrator-closure-report": {
      "description": "Report whether integrator can legally close the batch",
      "input": {
        "session_id": { "type": "string", "required": true },
        "ticket_id": { "type": "string", "required": false }
      },
      "output": { "description": "Closure legality report", "fields": { "closure_report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "integrator-closure-report", "--session-id", "{session_id}"]
      }
    },
    "check-ticket-scope": {
      "description": "Report if changed files stay inside claimed ticket scope",
      "input": {
        "ticket_id": { "type": "string", "required": true }
      },
      "output": { "description": "Scope report (CLEAN or SCOPE_BREACH)", "fields": { "scope_report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "check-ticket-scope", "--ticket-id", "{ticket_id}"]
      }
    }
  },
  "stdout_contract": {
    "last_line_json": true,
    "note": "tickets.py emits JSON on last line. tkt.sh emits JSON. Agent-executed procedures (create-bundle.md, generate-review.md) are non-stdout."
  }
}
  • opencode: Agents通过opencode运行时执行,agent-id映射到opencode会话
  • OMO: 编排层管理Agent生命周期和工单认领
  • 文件系统后端兼容Git,基础操作无需依赖数据库
  • 数据库后端需要PostgreSQL(通过skill-system-memory)
skill
{
  "schema_version": "2.0",
  "id": "skill-system-tkt",
  "version": "2.0.0",
  "capabilities": [
     "tkt-init", "tkt-create-bundle", "tkt-claim", "tkt-update", "tkt-add",
     "tkt-status", "tkt-close", "tkt-review", "tkt-list", "tkt-express",
     "tkt-roadmap-transition", "tkt-roadmap-status",
    "tkt-intake", "tkt-claim-db", "tkt-block", "tkt-close-db",
    "tkt-check-open", "tkt-claim-summary", "tkt-session-loop",
    "tkt-refresh-new", "tkt-refresh-inbox", "tkt-startup-flow",
    "tkt-integrator-closure", "tkt-check-scope",
    "pm-interpret", "pm-roadmap"
  ],
  "effects": ["fs.read", "fs.write", "db.read", "db.write", "proc.exec"],
  "operations": {
    "init-roadmap": {
      "description": "Initialize .tkt/ directory and roadmap.yaml",
      "input": { "project": { "type": "string", "required": true } },
      "output": { "description": "Initialized roadmap path", "fields": { "roadmap_path": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "init-roadmap", "--project", "{project}"]
      }
    },
    "create-bundle": {
      "description": "PM Agent creates a TKT bundle from user intent",
      "input": {
        "goal": { "type": "string", "required": true },
        "context": { "type": "string", "required": false },
        "track": { "type": "string", "required": false },
        "source_plan": { "type": "string", "required": false },
        "worktree": { "type": "boolean", "required": false },
        "carryover": { "type": "string", "required": false }
      },
      "output": { "description": "Bundle ID and ticket list", "fields": { "bundle_id": "string", "tickets": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "create-bundle", "--goal", "{goal}", "--track", "{track}", "--source-plan", "{source_plan}"],
        "agent": "scripts/create-bundle.md"
      }
    },
    "claim": {
      "description": "Claim a filesystem ticket within a bundle.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "ticket": { "type": "string", "required": true },
        "agent": { "type": "string", "required": true }
      },
      "output": { "description": "Claim result", "fields": { "claimed": "boolean", "ticket": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "claim", "--bundle", "{bundle}", "--ticket", "{ticket}", "--agent", "{agent}"]
      }
    },
    "update": {
      "description": "Update a filesystem ticket status and summary.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "ticket": { "type": "string", "required": true },
        "status": { "type": "string", "required": true },
        "summary": { "type": "string", "required": false },
        "evidence": { "type": "string", "required": false },
        "evidence_file": { "type": "string", "required": false },
        "reason": { "type": "string", "required": false }
      },
      "output": { "description": "Update result", "fields": { "ticket_id": "string", "new_status": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "update", "--bundle", "{bundle}", "--ticket", "{ticket}", "--status", "{status}"]
      }
    },
    "add": {
      "description": "Add a filesystem worker ticket with structured metadata.",
      "input": {
        "bundle": { "type": "string", "required": true },
        "title": { "type": "string", "required": true },
        "description": { "type": "string", "required": false },
        "category": { "type": "string", "required": false },
        "effort_estimate": { "type": "string", "required": false },
        "skills": { "type": "string", "required": false },
        "wave": { "type": "number", "required": false },
        "qa_scenarios": { "type": "string", "required": false },
        "depends_on": { "type": "string", "required": false },
        "source_plan": { "type": "string", "required": false },
        "source_ticket_index": { "type": "number", "required": false },
        "acceptance": { "type": "string", "required": false }
      },
      "output": { "description": "Added ticket result", "fields": { "ticket_id": "string", "bundle": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "add", "--bundle", "{bundle}", "--title", "{title}"]
      }
    },
    "express": {
      "description": "Manage express tickets without requiring a bundle.",
      "input": {
        "action": { "type": "string", "required": false },
        "title": { "type": "string", "required": false },
        "acceptance": { "type": "string", "required": false },
        "category": { "type": "string", "required": false },
        "effort_estimate": { "type": "string", "required": false },
        "wave": { "type": "number", "required": false },
        "source_plan": { "type": "string", "required": false },
        "source_ticket_index": { "type": "number", "required": false },
        "ticket_id": { "type": "string", "required": false },
        "agent": { "type": "string", "required": false },
        "files_changed": { "type": "number", "required": false },
        "evidence": { "type": "string", "required": false },
        "evidence_file": { "type": "string", "required": false }
      },
      "output": { "description": "Express ticket result", "fields": { "ticket_id": "string", "status": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "express"]
      }
    },
    "bundle-status": {
      "description": "Show bundle status with all tickets",
      "input": { "bundle": { "type": "string", "required": true } },
      "output": { "description": "Bundle status report", "fields": { "bundle": "object" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "status", "--bundle", "{bundle}"]
      }
    },
    "close-bundle": {
      "description": "Close bundle after worker completion and verification gates.",
      "input": { "bundle": { "type": "string", "required": true }, "merge": { "type": "boolean", "required": false } },
      "output": { "description": "Close result", "fields": { "closed": "boolean", "review_path": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "close", "--bundle", "{bundle}"]
      }
    },
    "list-bundles": {
      "description": "List all bundles and their status",
      "input": {},
      "output": { "description": "Bundle list", "fields": { "bundles": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "list"]
      }
    },
    "roadmap-transition": {
      "description": "Transition roadmap to a new stage with gate checks",
      "input": {
        "stage": { "type": "string", "required": true },
        "reason": { "type": "string", "required": true },
        "force": { "type": "boolean", "required": false }
      },
      "output": { "description": "Transition result", "fields": { "transition": "string", "new_stage": "string" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "roadmap-transition", "--stage", "{stage}", "--reason", "{reason}"]
      }
    },
    "roadmap-status": {
      "description": "Show roadmap stage, bundle summary, and allowed transitions",
      "input": {},
      "output": { "description": "Roadmap status", "fields": { "project": "string", "stage": "string", "allowed_transitions": "array" } },
      "entrypoints": {
        "unix": ["bash", "{skill_dir}/scripts/tkt.sh", "roadmap-status"]
      }
    },
    "generate-review": {
      "description": "Generate review bundle post-closure",
      "input": { "bundle": { "type": "string", "required": true } },
      "output": { "description": "Review bundle", "fields": { "review_path": "string" } },
      "entrypoints": { "agent": "scripts/generate-review.md" }
    },
    "intake-ticket": {
      "description": "Create or sync a durable ticket from note_tasks intake",
      "input": {
        "ticket_id": { "type": "string", "required": false },
        "title": { "type": "string", "required": false },
        "from_note_tasks": { "type": "boolean", "required": false }
      },
      "output": { "description": "Canonical ticket record", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "intake-ticket"]
      }
    },
    "list-tickets": {
      "description": "List durable workflow tickets",
      "input": {
        "unresolved_only": { "type": "boolean", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Ticket list", "fields": { "tickets": "array" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "list-tickets"]
      }
    },
    "claim-ticket": {
      "description": "Claim a ticket for the current session (DB-backed, conflict-safe)",
      "input": {
        "ticket_id": { "type": "string", "required": true },
        "session_id": { "type": "string", "required": true }
      },
      "output": { "description": "Claimed ticket", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "claim-ticket", "--ticket-id", "{ticket_id}", "--session-id", "{session_id}"]
      }
    },
    "block-ticket": {
      "description": "Mark a ticket as blocked",
      "input": {
        "ticket_id": { "type": "string", "required": true },
        "reason": { "type": "string", "required": false }
      },
      "output": { "description": "Blocked ticket", "fields": { "ticket": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "block-ticket", "--ticket-id", "{ticket_id}"]
      }
    },
    "close-ticket": {
      "description": "Close the currently claimed ticket (runs refresh first)",
      "input": {
        "session_id": { "type": "string", "required": true },
        "ticket_id": { "type": "string", "required": false },
        "resolution": { "type": "string", "required": false }
      },
      "output": { "description": "Closed ticket + refresh status", "fields": { "ticket": "object", "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "close-ticket", "--session-id", "{session_id}"]
      }
    },
    "check-open-tickets": {
      "description": "Report unresolved tickets",
      "input": { "session_id": { "type": "string", "required": false } },
      "output": { "description": "Open ticket report", "fields": { "report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "check-open-tickets"]
      }
    },
    "claim-summary": {
      "description": "Batch/session claim ownership summary with collaboration policy",
      "input": {
        "session_id": { "type": "string", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Claim summary", "fields": { "claim_summary": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "claim-summary"]
      }
    },
    "session-loop": {
      "description": "Run the legal worker loop for one session",
      "input": {
        "session_id": { "type": "string", "required": true },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Loop state", "fields": { "loop_state": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "session-loop", "--session-id", "{session_id}"]
      }
    },
    "refresh-new-tasks": {
      "description": "Re-read note_tasks ### New and ingest new work",
      "input": {
        "batch_id": { "type": "string", "required": false },
        "trigger_point": { "type": "string", "required": false }
      },
      "output": { "description": "Refresh status", "fields": { "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "refresh-new-tasks"]
      }
    },
    "refresh-review-inbox": {
      "description": "Parse review inbox and ingest inbox-derived tickets",
      "input": {
        "batch_id": { "type": "string", "required": false },
        "trigger_point": { "type": "string", "required": false }
      },
      "output": { "description": "Inbox refresh status", "fields": { "refresh_status": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "refresh-review-inbox"]
      }
    },
    "startup-flow": {
      "description": "Startup/claim-loop context from zero to review handoff",
      "input": {
        "session_id": { "type": "string", "required": false },
        "batch_id": { "type": "string", "required": false }
      },
      "output": { "description": "Startup context", "fields": { "startup_context": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "startup-flow"]
      }
    },
    "integrator-closure-report": {
      "description": "Report whether integrator can legally close the batch",
      "input": {
        "session_id": { "type": "string", "required": true },
        "ticket_id": { "type": "string", "required": false }
      },
      "output": { "description": "Closure legality report", "fields": { "closure_report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "integrator-closure-report", "--session-id", "{session_id}"]
      }
    },
    "check-ticket-scope": {
      "description": "Report if changed files stay inside claimed ticket scope",
      "input": {
        "ticket_id": { "type": "string", "required": true }
      },
      "output": { "description": "Scope report (CLEAN or SCOPE_BREACH)", "fields": { "scope_report": "object" } },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tickets.py", "check-ticket-scope", "--ticket-id", "{ticket_id}"]
      }
    }
  },
  "stdout_contract": {
    "last_line_json": true,
    "note": "tickets.py emits JSON on last line. tkt.sh emits JSON. Agent-executed procedures (create-bundle.md, generate-review.md) are non-stdout."
  }
}