| name | bridge-pacing |
| description | Translate a `[BRIDGE PACING]` 15-min calibration tick into per-agent throttle adjustments. The bridge measures the team's actual rate of consumption and gives you a verdict (SFORO / MARGINE / ALLINEATO) plus the per-agent share + cadence needed to choose WHO to slow down and BY HOW MUCH. Open this skill ONLY when a `[BRIDGE PACING]` line lands; the routine `[SENTINELLA]` orders use a different flow (`sentinel-orders`). |
| allowed-tools | Bash(python3 /app/shared/skills/throttle-config.py *), Bash(jht-tmux-send *) |
bridge-pacing — data-driven throttle calibration
The bridge runs a measurement window every 15 min (aligned to :00/:15/:30/:45 UTC). At each window-close it writes one line into the Captain's pane that summarises the team's actual rate and tells you which way to bias the throttle. This is not a Sentinel order — it is a calibration signal you act on with throttle-config.py.
Message shape
[BRIDGE PACING] HH:MM UTC window=15m (effettivi Xm) samples=N |
usage=U% reset_in=Rh reset_at=THH:MM UTC (proj=P% — INFO, secondario non-driver) |
vel_team=V%/h | vel_target=T%/h (per chiudere a TGT% al reset) [schedule+ratio phase=ON] |
ratio=K kT/% (team Σ kT / Δusage) |
agenti: name=p%/h [kT/Xm → kT/h ÷ K = p%/h, share s%, cadenza c/min (n chk in Xm)] ; ... |
VERDETTO: SFORO|MARGINE|ALLINEATO ...
TGT is the dynamic target chosen by the bridge:
- 24/7 config or no schedule →
TGT=92 (band center, historical default)
- work-hours config + provider with weekly cap (Codex/Claude) →
TGT is the % needed at reset so the weekly budget is distributed exactly across the user's active hours. Example: office hours 9-18 on Codex Pro → TGT≈76.
- work-hours config + Kimi (no weekly cap) →
TGT=92 (band center fallback).
The [schedule+ratio phase=ON] tag in parentheses is the source of the target — band_center (no work-hours), schedule+ratio (full work-hours-aware), schedule+band (work-hours + Kimi fallback). Use it to debug unexpected targets.
Fields you actually use
| Field | What it tells you |
|---|
vel_team | measured team rate, in budget %-points per hour |
vel_target | rate that would land at TGT% at reset (centre of the ±10pt band around TGT) |
share s% | per-agent weight on the total rate (Σ shares ≈ 100%) — tells you WHO to slow down |
cadenza c/min | per-agent jht-throttle calls per minute in the window — tells you HOW MUCH to add to the config |
VERDETTO | actionable summary; map directly to the table below |
⚠️ proj is INFO only — do NOT act on it. It is a volatile extrapolation of
short-window velocity (e.g. it printed proj=-8.66% while the team was merely a
hair under target). The control loop is vel_team vs vel_target (both
weekly-aware) + weekly_remaining. Ignore proj for throttle/spawn decisions.
Verdict → action
| Verdict | Meaning | Action |
|---|
SFORO +X%/h → riduci Y% | vel_team exceeds target by X points/h. Cut Y% of the rate. | Increase throttle-config for the agents with high share (top 1-2) |
MARGINE −X%/h → puoi salire Y% | vel_team below target. You have headroom. | Zero or reduce the throttle on throttled agents (priority: bottleneck role) |
ALLINEATO Δ ±0.2%/h | inside tolerance. | do nothing, wait for the next tick |
💡 X%/h vs Y% are the same thing in two units. Y = X / vel_team × 100.
Calibration formula (the one new thing here)
To obtain a f% rate reduction on an agent with cadence c checkpoint/min, the duration to put into throttle-config is:
durata_sec = (f / 100) × 60 / c
The intuition: every jht-throttle call adds durata_sec of pause. Over 60s the agent calls it c times → adds c · durata seconds of pause per minute → fractional rate cut = c · durata / 60. Solve for durata.
Worked example — concentrate the cut on one agent
Tick: SFORO +4.35%/h → riduci 19%
analista-1: share 47%, cadenza 0.6/min
Push almost the entire cut onto analista-1:
- fraction on analista-1 ≈ 19% / 47% ≈ 40%
durata_sec = 0.40 × 60 / 0.6 = 40s
- →
throttle-config.py set analista-1 40
Worked example — spread the cut over two agents
Tick: SFORO +4.35%/h → riduci 19%
analista-1: share 47%, cadenza 0.6/min
scout-1: share 26%, cadenza c_scout
Combined weight 47 + 26 = 73%. Spread the 19% proportionally:
- fraction per agent ≈ 19% / 73% ≈ 26%
- analista-1:
0.26 × 60 / 0.6 = 26s
- scout-1:
0.26 × 60 / c_scout
- → one
bulk-set write atomically:
python3 /app/shared/skills/throttle-config.py bulk-set \
analista-1=26 scout-1=<derived from c_scout>
When releasing throttle (MARGINE)
If the verdict is MARGINE −X%/h → puoi salire Y%:
- Pick the role you want to accelerate (priority: the current bottleneck —
pipeline-triage if unsure).
- Reduce its current throttle by approximately
Y% (or zero it if it was a small value).
- Do not zero everyone at once — you would oscillate into a SFORO at the next tick.
Cadence after a config change
- After any change, wait 2-3 ticks (≈30-45 min) before intervening again.
- The pacing is already your synthesis — do not add extra
rate_budget live calls in between (they inflate the Sentinel's velocity_smooth).
- If after 3 ticks the verdict is still SFORO, double the durations on the same agents (linear → geometric); if still MARGINE, halve.
Anti-patterns
- ❌ Reading only
VERDETTO and ignoring share / cadenza: you cut blindly across all agents and hit the cheap roles (Scorer, Analyst) before the expensive ones (Writer, Critic).
- ❌ Treating a single SFORO tick as a permanent state: 1 tick is noise, 2 consecutive ticks is signal.
- ❌ Mixing this flow with
sentinel-orders ones: a [BRIDGE PACING] and an [URG] RALLENTARE can land within minutes of each other. The [URG] always wins — apply it first, the next pacing will re-measure.
- ❌ Pushing pacing-derived numbers via tmux to agents (
[INFO] sleep 40s). Always go through throttle-config.py — agents read the file, do not parse your tmux body.
See also
sentinel-orders — routine ticks, throttle 0-4 levels, emergencies.
bridge-mailbox — drain pacing verdicts you missed during a long turn (the bridge appends to a JSONL even if the live tmux send failed).
throttle — the throttle-config.py CLI reference and the per-agent state file.
pipeline-triage — when MARGINE means "spawn one more at the bottleneck" rather than just zeroing throttle.