-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path.aiball.yaml.example
More file actions
293 lines (252 loc) · 14.3 KB
/
Copy path.aiball.yaml.example
File metadata and controls
293 lines (252 loc) · 14.3 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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# aiball per-project config (.aiball.yaml)
#
# Drop at the project root to enable the autopoll hook. `{}` (empty YAML)
# is enough to turn autopoll on; everything below has a sensible default.
# Full reference + layering rules: docs/CONFIGS.md.
# Pilot from the CLI: `aiball check`, `aiball autopoll enable|disable|tone X`.
# --- autopoll -----------------------------------------------------------------
autopoll:
# Master switch. The hook in ~/.claude/settings.json is global; this is
# the per-project opt-in.
enabled: true
# false = persistent reminder (re-fires after throttle_seconds);
# true = one-shot (only notify when a strictly newer ping arrives).
volatile: false
# Reminder cadence (ignored when volatile). 0 = every Stop (spammy).
throttle_seconds: 120
# Reminder tone: hint | directive | imperative.
tone: directive
# Up to N recent unread ticket titles in the hook reason. 0 = count only.
include_recent_tickets: 3
# When true, the open-tickets count is itself a trigger (notify even
# without unread pings). false = display only.
backlog: true
# --- consumer identity --------------------------------------------------------
# Canonical source for this project's agent + project name. Resolution
# order: AIBALL_AGENT/AIBALL_PROJECT env > this block > .mcp.json env
# (DEPRECATED) > defaults (project = basename(cwd), agent = <project>-claude).
# consumer:
# agent: my-agent
# project: my-project
# # If true, agent is "assignment-only": ticket_engage skips the claimable
# # pool and only returns explicitly assigned tickets.
# no_claim: false
# # Multi-agent role (sugar over the primitives above). `lead` = the
# # maintainer agent (owner subscription, can claim) — the default when
# # unset. `crew` = an assignment-only worker (follower subscription,
# # no_claim forced). The `claude-loop --role lead|crew` flag overrides
# # this per launch. Leave unset for the classic single-agent workflow.
# role: lead
# --- claude-loop --------------------------------------------------------------
# The tmux wrapper around `claude`. CLI flags (--interval, --user-grace, …)
# still win over this block when explicitly passed.
claude_loop:
# Heartbeat tick (seconds). Drives the bar counters / view refresh /
# SSE reconnect and an anti-stuck wake fallback. Not the wake cadence.
interval_seconds: 30
# Drain tempo (seconds). The single periodic wake cadence: when idle
# with work pending, the loop drains the queue every wake_tempo_seconds
# (this is the envelope countdown in the bar). An incoming event waits
# at most this long before waking. Lower = snappier wakes, more polling.
wake_tempo_seconds: 10
# Boot-grace before settleBoot fires. The pane probe can leave [boot]
# earlier if it detects the prompt.
boot_grace_seconds: 60
# Rotating pane-capture cache, in FRAMES. 0 (the default) = no cache.
#
# The loop reads its state — busy, idle prompt, compacting, crash banners —
# by matching text against a screen capture, so those rules are only as good
# as the screens they were written against. Turning this on keeps the newest
# N screens under `<state_dir>/pane-captures/`, ready to read back with
# `claude-loop capture --last <n>` when a detector starts lying.
#
# Only a frame that DIFFERS from the previous one is stored, so N counts
# distinct screens rather than ticks and an idle loop costs nothing.
#
# It is off by default because it is a debugging corpus: switch it on for a
# project whose pane detectors you are actively tuning, and leave it off
# everywhere else.
pane_cache_frames: 0
# Floor INVIOLABLE — boot phase ne peut pas finir avant ce minimum
# (default 30 s). Couvre le flicker au démarrage où des hooks early
# peuvent prétendre que claude est ready avant qu'il ait vraiment
# dessiné son prompt. Rien n'autorise à quitter [boot] inside this
# window — pas le hook, pas la pane probe.
boot_min_seconds: 30
# Presence-hold duration (seconds). Typing in the pane arms a presence
# hold of this length (visible as `wait` on the bar) during which
# auto-wakes stay skipped and `AskUserQuestion` dialogs stay allowed;
# F9 cycles the hold by hand (away → hold → ∞). 600 = 10 min.
presence_hold_seconds: 600
# WAIT default when neither --wait nor --no-wait is passed. Global CLI
# default stays no-wait (eager boot drain); flip true to yield boot-grace
# for a human take-over without typing --wait each time.
wait: false
# How long the wake-in-flight marker stays "fresh" after the timer
# touches it pre-send-keys (ms). The UserPromptSubmit hook uses this
# to distinguish auto-wake from human input.
wake_in_flight_ttl_ms: 2000
# When ON, pressing ESC in the loop pane arms the presence hold
# (so the loop stops auto-pinging while you take over). Requires the
# PTY proxy (the default launch path).
esc_takeover: true
# AFK key — F9 cycles 3 states: `AFK` (autonomous loop, dim) →
# `NOT AFK 10m` (jaune countdown) → `NOT AFK ∞` (rouge indefinite)
# → back to `AFK`. Typing also arms / refreshes the 10m hold
# (no-op in ∞ mode — only F9 releases that). Bar shows `wait` while
# armed, status-right reads `Nm NOT AFK:F9` (jaune 10m) /
# `∞ NOT AFK:F9` (rouge ∞) / `AFK:F9` (dim, off). Chord notation:
# VS Code, SPACE = OR. f9 has no OS/tmux/claude conflict. Avoid alt+…
# (WM/terminal), ctrl+s/q (flow control), ctrl+c/d/z/b and readline
# keys, f1/f10/f11/f12. Verify any candidate with
# `claude-loop debug-keys`. Requires the PTY proxy.
afk_key: "f9"
# Post-fire key-repeat debounce (ms): a held chord repeats the same
# bytes; within this window after a toggle they're swallowed.
afk_window_ms: 400
# Drained-backlog reminder strategy. Fires when pings=0 + actionable=0
# but open>0 (tickets awaiting YOUR accept/reject/reply).
# Syntax: kind[:PT…[/PT…]] (ISO-8601 durations).
# silent — never remind.
# once — one wake when the pool first empties.
# stale[:PT2H] — remind only after the backlog stayed untouched
# for the window (defaults to PT2H).
# backoff[:PT10M[/PT1D]] — first reminder at +base, then doubles up to cap.
# persistent[:PT30M] — every eligible tick spaced by ≥ the param.
drained_strategy: "once"
# Minimum log level for the timer + hooks (PSR-3 / RFC 5424). Levels:
# debug | info | notice | warning | error | critical | alert | emergency.
log_level: "info"
# `--permission-mode` passed to the claude binary. Empty (default) omits the
# flag → claude's interactive `default` mode: it PROMPTS for permissions and
# does NOT sandbox bash. Set "auto" for an unattended/AFK loop: claude
# auto-approves sandbox-safe commands and SANDBOXES the rest (no network/host
# access) — required for fully autonomous runs, but it's also what makes
# host/network commands (e.g. `make t1000-status`) see a wrong/empty result.
# An AFK loop with this empty will STALL on the first permission prompt.
# permission_mode: "" # default: omitted (no sandbox, prompts)
# permission_mode: "auto" # unattended/AFK: auto-approve + sandbox
# Which PTY-proxy backend to launch on Unix (live human-typing detection).
# Default = the cross-platform Rust proxy (cl-pty-proxy); if it isn't built
# the launch transparently falls back to the Python proxy (pty-proxy.py).
# Set "python" to force the Python proxy. Windows always uses Rust. Only
# affects newly started loops.
# proxy_impl: "python"
# Custom wake gates. Each runs at heartbeat; on trigger its message is
# prepended to the wake CTA. Two forms: built-in `type:` or custom `cmd:`.
# `blocks: true` makes the wake lead with the gate and suppress the
# "engage #N" directive. See docs/CONFIGS.md for the full grammar.
# gates:
# - type: unmerged_pr
# # - type: unmerged_pr
# # blocks: true
# # - name: preflight
# # cmd: "make preflight"
# # message: "preflight failing — fix before new work"
# --- claude binary ------------------------------------------------------------
# Spawn-time options for `claude` itself (distinct from claude_loop, the
# machinery around it).
claude:
# Auto-inject `--resume` at spawn unless already passed on the CLI.
# An explicit --resume / --resume=<id> / --no-resume always wins.
# Default true (claude-loop resumes the most recent session by default).
always_resume: true
# How this agent's claude session is chosen. Matters for multi-agent
# projects (a lead + crew workers) where several persistent agents must NOT
# all converge on "the most recent session". Applies to the LEAD; crew
# workers are always `managed` (each gets its own stable session).
# auto — default. First run: start a fresh session; aiball detects the
# session id claude uses and records it in `.aiball-session_id`
# (gitignore it), then resumes exactly that session next time.
# legacy — the historical behavior: `--resume` + always_resume above
# (picks the most recent session for the directory). No id tracking.
# managed — assign a deterministic session per agent (derived, restart-proof)
# and resume exactly that one, no picker.
# fixed — use the explicit id in `session_id` below.
session_mode: auto
# Session id used only when session_mode is `fixed` (must be a valid UUID).
# session_id: "00000000-0000-4000-8000-000000000000"
# --- project type -------------------------------------------------------------
# Picked up by the MCP `welcome` tool to choose the onboarding kit. Out of
# the box: `public` (strict scrubbing) and `private`. Validated at call
# time against the install's `welcome/<type>/` folders. Absent here = `public`.
project_type: public
# --- tmux bar colours ---------------------------------------------------------
# Each value is a raw tmux colour token (`colour16`, named like `red`, or
# `#0087ff`). Layered: shipped defaults → ~/.config/aiball/config.yaml
# `colors:` → this block. The bar has TWO foregrounds: the black "island"
# (`island_fg`) and the state-coloured region (`bar_fg`).
# colors:
# island_fg: "colour15" # `claude-…` on the black island (white)
# bar_fg: "colour16" # name / [state] / afk on the coloured bar (black)
# afk_label_fg: "colour238" # dim `· afk:` label
# prompt_input_fg: "colour214" # the `❯` glyph when the prompt holds unsent text
# busy_bg: "colour33" # claude working (electric blue)
# idle_bg: "colour240" # at the prompt (dark grey)
# boot_bg: "colour178" # booting (yellow)
# link_down_bg: "colour160" # IPC link to the proxy lost — bar may be stale (red)
# --- upstream provider bindings -----------------------------------------------
# Renders `<prefix>#NNN` refs as clickable chips in markdown bodies, AND lets
# the bare `gh#N` form resolve to a repo for `ticket import` (coupling).
# Key = aiball project name. Per-provider: at most ONE entry can have
# `default: true`. The self-contained `gh:owner/repo#N` form needs no binding.
# The API TOKEN for coupling is host-level and lives in the GLOBAL config
# (~/.config/aiball/config.yaml → upstream_auth), never here. See docs/UPSTREAM.md.
# upstream:
# my-project:
# - kind: github
# ref: github:owner/repo
# default: true
# # Optional per-repo wire: auto (default) | gh | http. `gh` uses the
# # GitHub CLI's own credential (no token stored here); `http` calls the
# # API directly. Host-wide default: `upstream_transport:` in the global
# # config. A pinned wire never silently falls back — see docs/UPSTREAM.md.
# transport: gh
# # Watch this coupling? pull (default) = announce upstream changes in the
# # thread; off = stay linked but don't look. Host-wide default lives in
# # the global config as `upstream_sync:`. Nothing is ever copied either
# # way — see docs/UPSTREAM.md.
# sync: pull
# --- wake-CTA / state-prompt overrides ----------------------------------------
# Shipped defaults at `config/defaults/claude-loop-pings.yaml` already
# work — this block is optional and only needed to localize wording,
# tune directiveness, or tweak for a multi-agent setup. Layering:
# shipped → ~/.config/aiball/config.yaml → this block (slot-grain replace).
# Placeholder grammar + slot shapes documented in docs/CONFIGS.md.
# prompts:
# wake_lead:
# directive: ["fyi:", "heads up —", "quick note:"]
# hint: ["btw,", "fyi,"]
# imperative: ["**heads up**:", "**ACTION**:"]
# wake_master:
# directive: "{head_comment_hashid:+{head_body:+{head_body} }(#{head_id} / #{head_comment_hashid})}{head_kind:+new ticket #{head_id}{head_title:+: {head_title}}}{head_lifecycle:+#{head_id} {head_lifecycle}{head_title:+: {head_title}}}{backlog_mode:+{culture} look #{head_id}{head_title:+: {head_title}}. Triage the ticket.}{no_head:+{culture} {lead}}"
# # One-shot prompt fired at boot exit (after the tail-grace seal). Prepended
# # to the boot-ended-drain wake — the agent receives a single combined prompt.
# # Set to "" (empty) to opt out per-project.
# post_boot_skill_reminder: "Use the /aiball skill to triage your queue. Check `unread` and `actionable` first."
# --- ticket-text linkifier patterns -------------------------------------------
# Merge by `id` (3 layers, ADDITIVE: shipped defaults always run; entries
# here OVERRIDE by reusing an id or ADD with a fresh id). Regex validated
# at load; invalid entries logged + dropped.
# formatting:
# patterns:
# - id: ticket
# match: "#[Bb][._/-]?(\\d+)\\b"
# canonical: "[B-{1}]"
# href: "/b/{1}"
# class: "ticket-ref"
# - id: jira
# match: "\\b(PROJ-\\d+)\\b"
# canonical: "{1}"
# href: "https://jira.example.com/browse/{1}"
# class: "external-ref"
# --- config-defined tags ------------------------------------------------------
# Read-only in the Tags admin panel (lock badge, no delete). Layering is
# COMPOSITE — every layer ADDS (unlike prompts/formatting which replace).
# A tag's display order follows the LAST layer that mentions it.
#
# Per-project file: bare list = "tags for this project". For cross-project
# tags, use the project-keyed map in the global file (~/.config/aiball/config.yaml).
# tags:
# - claude-code
# - { name: hook, color: "#0ea5e9", note: "settings.json hooks" }