forked from Sugar-Coffee/stokowski
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathworkflow.example.yaml
More file actions
263 lines (244 loc) · 11.6 KB
/
workflow.example.yaml
File metadata and controls
263 lines (244 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# =============================================================================
# Stokowski — Example: single Linear project mapped to a single repo (1:1)
# =============================================================================
#
# This is the simplest Stokowski setup: one Linear project, one Git repo,
# one state machine pipeline. No `repos:` registry, no triage, no
# multi-repo routing. If your team operates with a single product/repo
# per Linear project, start here.
#
# Other worked examples:
# workflow.multi-repo.example.yaml — one project spanning N repos
# (label-driven routing, default repo)
# workflow.multi-repo-triage.example.yaml — same + triage agent that
# re-labels tickets via
# `workflow:triage`
#
# Stokowski re-reads this file on every poll tick — changes take effect
# without restart.
#
# Prompt files live in the prompts/ directory. Each agent state references
# its prompt via the `prompt` field. A global prompt (shared preamble) is
# injected before the stage-specific prompt when set.
#
# Linear states mapping:
# active → the "working" state for agent stages
# review → human review / PR review state
# gate_approved → human approved a gate (triggers transition)
# rework → human requested changes (triggers rework_to)
# terminal → list of done/closed states
#
# State types:
# agent — Stokowski dispatches Claude Code in this state
# gate — pauses for human review; approve → next, rework → rework_to
# terminal — issue is finished; workspace cleaned up
# =============================================================================
# ---------------------------------------------------------------------------
# Tracker
# ---------------------------------------------------------------------------
tracker:
kind: linear
project_slug: "abc123def456" # hex slugId from your Linear project URL
api_key: "lin_api_your_key_here" # your Linear API key — agents inherit this
# ---------------------------------------------------------------------------
# Linear state name mapping
# ---------------------------------------------------------------------------
# These map Stokowski's internal lifecycle roles to your Linear state names.
# You can rename values to match your Linear setup (e.g. todo: "Ready"),
# but all six roles are required — removing or reordering them will break
# the dispatch and gate protocol.
linear_states:
todo: "Todo" # issues picked up from this state
active: "In Progress" # moved here automatically when agent starts
review: "Human Review" # agent pauses here at a gate for human review
gate_approved: "Gate Approved" # human approved — agent advances to next state
rework: "Rework" # human requested changes — agent re-enters rework target
terminal: # issues in these states stop any running agent
- Done
- Closed
- Cancelled
- Canceled
- Duplicate
# ---------------------------------------------------------------------------
# Polling
# ---------------------------------------------------------------------------
polling:
interval_ms: 15000 # 15 seconds between ticks
# ---------------------------------------------------------------------------
# Workspace
# ---------------------------------------------------------------------------
workspace:
root: ~/code/stokowski-workspaces
# ---------------------------------------------------------------------------
# Hooks — shell scripts run in the workspace directory
# ---------------------------------------------------------------------------
# In this 1:1 layout (no `repos:` section), hooks pass through to the shell
# verbatim — Stokowski does NOT Jinja-render them. This means shell bodies
# containing literal `{`/`}` (e.g., `!f() { ...; }; f` credential helpers)
# continue to work unchanged. If you migrate to multi-repo, hooks will be
# rendered with a `{{ repo.* }}` namespace — see the multi-repo examples.
hooks:
after_create: |
git clone --depth 1 git@github.com:your-org/your-repo.git .
npm install
before_run: |
git fetch origin main
git rebase origin/main 2>/dev/null || git rebase --abort
timeout_ms: 120000
# ---------------------------------------------------------------------------
# Claude defaults (inherited by all agent states unless overridden)
# States using runner: codex will use the Codex CLI instead.
# ---------------------------------------------------------------------------
claude:
permission_mode: auto
model: claude-sonnet-4-6
max_turns: 20
turn_timeout_ms: 3600000 # 1 hour per turn
stall_timeout_ms: 300000 # 5 minutes with no output → kill
# ---------------------------------------------------------------------------
# Agent concurrency
# ---------------------------------------------------------------------------
agent:
max_concurrent_agents: 4
max_retry_backoff_ms: 300000 # 5-minute cap on exponential backoff
max_concurrent_agents_by_state:
investigate: 2 # allow 2 concurrent investigations
implement: 2
code-review: 1 # serial reviews prevent merge conflicts
# ---------------------------------------------------------------------------
# Prompts
# ---------------------------------------------------------------------------
prompts:
global_prompt: prompts/global.example.md
# ---------------------------------------------------------------------------
# Server (optional web dashboard)
# ---------------------------------------------------------------------------
server:
port: 4200
# ---------------------------------------------------------------------------
# Docker isolation (optional — agents run as sibling containers)
# ---------------------------------------------------------------------------
# docker:
# enabled: true
# default_image: "stokowski/claude-agent:latest"
# inherit_claude_config: true
# host_claude_dir: "${HOST_HOME}/.claude"
# # DooD shim fields — required when the orchestrator itself runs in a
# # container AND inherit_claude_config is true. Stokowski refuses to start
# # in DooD mode without these to prevent host plugin files from being
# # rewritten. See CLAUDE.md (Docker mode) for setup.
# host_claude_dir_mount: "/host-claude" # where host_claude_dir is RO-mounted inside the orchestrator
# plugin_shim_host_path: "${HOST_PLUGIN_SHIM}" # host-resolvable shim dir (e.g. ${HOME}/.stokowski-plugin-shim)
# plugin_shim_container_path: "/plugin-shim" # where plugin_shim_host_path is RW-mounted inside the orchestrator
# extra_env:
# - GITHUB_TOKEN
# - CLAUDE_CODE_OAUTH_TOKEN # required for Claude Code auth in containers
# extra_volumes:
# - "${HOST_HOME}/.ssh:/root/.ssh:ro"
# - "${HOST_HOME}/.gitconfig:/root/.gitconfig:ro"
#
# Authentication for Docker mode:
# Claude Code in containers cannot use interactive OAuth login. Set one of:
# ANTHROPIC_API_KEY — standard API key (API plan required)
# CLAUDE_CODE_OAUTH_TOKEN — long-lived token for Pro/Max users
#
# Generate an OAuth token by running `claude setup-token` in your terminal,
# then add it to your .env file:
# CLAUDE_CODE_OAUTH_TOKEN=your_generated_token_here
#
# Add CLAUDE_CODE_OAUTH_TOKEN to extra_env so it reaches agent containers.
# ---------------------------------------------------------------------------
# State machine
# ---------------------------------------------------------------------------
#
# Order matters: the first agent state is the entry state for new issues.
#
# Transitions fire automatically on agent success or human action:
# - Agent finishes successfully → "complete" transition
# - Human approves a gate → "approve" transition
# - Human requests rework → rework_to target
#
states:
# ── 1. Investigate ──────────────────────────────────────────────────────
# Read the codebase, understand the problem, post an investigation summary.
# Uses Opus for deeper reasoning. Low turn count — investigation only.
investigate:
type: agent
prompt: prompts/investigate.example.md
linear_state: active
model: claude-opus-4-6
max_turns: 8
session: inherit
transitions:
complete: research-review
# ── 2. Research Review (gate) ───────────────────────────────────────────
# Human reviews the investigation before implementation starts.
# Rework loops back to investigate.
research-review:
type: gate
linear_state: review
rework_to: investigate
max_rework: 3
transitions:
approve: implement
# ── 3. Implement ────────────────────────────────────────────────────────
# Write code, create branch, run tests, open PR.
# Uses Sonnet for fast iteration. Higher turn count for complex work.
implement:
type: agent
prompt: prompts/implement.example.md
linear_state: active
model: claude-sonnet-4-6
max_turns: 30
session: inherit
transitions:
complete: implementation-review
# ── 4. Implementation Review (gate) ─────────────────────────────────────
# Human reviews the PR before automated code review.
# Rework loops back to implement.
implementation-review:
type: gate
linear_state: review
rework_to: implement
max_rework: 5
transitions:
approve: code-review
# ── 5. Code Review ─────────────────────────────────────────────────────
# Automated adversarial review: fresh session, no prior context.
# Opus reviews the diff and posts findings.
# Tip: set runner: codex here to get a second-opinion from a different
# provider — different states can use different runners in the same run.
code-review:
type: agent
prompt: prompts/review.example.md
linear_state: active
runner: claude # "claude" (default) or "codex"
model: claude-opus-4-6
max_turns: 10
session: fresh # no prior context — adversarial review
transitions:
complete: merge-review
# ── 6. Merge Review (gate) ──────────────────────────────────────────────
# Human reviews the code review findings and decides to merge or rework.
# Rework goes back to implement (not code-review).
merge-review:
type: gate
linear_state: review
rework_to: implement
max_rework: 5
transitions:
approve: merge
# ── 7. Merge ────────────────────────────────────────────────────────────
# Merge the PR and clean up. Short turn count — just the merge.
merge:
type: agent
prompt: prompts/merge.example.md
linear_state: active
max_turns: 5
session: inherit
transitions:
complete: done
# ── 8. Done (terminal) ─────────────────────────────────────────────────
done:
type: terminal
linear_state: terminal