Skip to content

v5.26.0 — Team Tasks accept any agent id (PS company loop on the ledger)

Choose a tag to compare

@ucsandman ucsandman released this 20 Aug 15:33
· 55 commits to main since this release

Changed

  • Team Tasks accept any agent id, not just claude|openclaw|wes. The
    /api/team-tasks routes validated from_agent, to_agent and lead_agent
    against a two-name enum that mirrored the original /team ledger client, so a
    second multi-agent system could not post to the same ledger: the Practical
    Systems company loop - MoltFire (CEO), Forge (assurance), Cinder
    (communications), the ps-* specialists and Mission Control itself - was
    rejected with 400 on every event. Participants are now any lowercase slug
    (^[a-z][a-z0-9_-]{0,39}$, isTeamAgentId in the repository); the closed list
    was never the trust-boundary check, the shape is. origin gains
    company-loop. Statuses and event types are unchanged, so the existing ledger
    client syncs exactly as before. MCP tool descriptions and the platform guide
    describe the id as a slug instead of an enum.

  • The calibration controller now loosens as well as tightens. It had one arm:
    above the calibrated threshold θ it could raise allow/warn to
    require_approval, and below θ it could do nothing at all. That made the
    controller's own target unreachable — θ rose on every approval, but the policy
    interruptions underneath it stood regardless, so the engine could only ever add
    interruptions to an operator's day and never remove one. The new demote arm
    downgrades a policy's require_approval to warn below θ, which is what makes
    the interruption set it controls actually {score ≥ θ}.

    Bounded four ways, each closing a different way relief could be unearned: it
    waits for 10 adjudications; it never reaches past reliefCeiling — the highest
    risk score the operator personally approved and has not since denied at or above,
    which starts at −1 so switching the mode on can never relieve a band nobody has
    ruled on, and which one deny at score s retracts above s on the next call; it
    never touches an ungrantable rule or an agent under a standing denial alarm;
    and it demotes to warn, never allow, so the action stays on /decisions with
    the gating reasons preserved. Blocks remain absolute, and no policy row is ever
    edited — standing policy changes still route through the human-ratified /policies
    rails.

    New mode relief on /calibration runs the demote arm alone, for an operator who
    wants interruptions removed without any added; active now runs both arms. Relief
    is one click (it only reduces enforcement); active keeps its two-step confirm.
    The loosening evidence queries count a relieved decision as an interruption that
    still happened, so demoting cannot erase the signal that justified it.

Fixed

  • Read-only git log no longer scores as rm -rf /. DESTRUCTIVE_GOAL_PATTERNS
    now requires format to take a device object (format c:, format /dev/sda,
    format the disk) instead of rejecting one flag spelling. The 2026-07-01
    (?<!-)\bformat\b fix rejected --format= but not --date=format: (the preceding
    character is =, not -), so every git-log command carrying --date=format: took
    +20 destructive and hit the 100 clamp — 1,759 approval interruptions in seven days
    in one org. npm run format was affected the same way. Pinned by three new golden
    vectors; server-side only (the Python client classifier already graded format as a
    readonly verb).
  • A risk_threshold policy at or above tuning's cap is no longer unreachable by both
    engines.
    Loosening used to skip every risk_threshold policy on the grounds that
    the tuning engine owned them, but tuning's only relaxation computes
    min(threshold + 10, 95) and requires that to exceed the current threshold — so a
    policy at 100 got nothing from either side. tuningCanMove() now decides the handoff.

Added

  • Interruption budget — the first relaxation path that fires without the operator
    adjudicating anything. Every previous mechanism (allow_grant, precedent, approval
    pause, scope relax, deactivate, threshold raise) gates on resolved approvals, but
    interruption volume is exactly what stops a human resolving them. This one reads
    volume only.
    • Policy grain: past DASHCLAW_INTERRUPTION_BUDGET interruptions per 24h (default
      50), a rule is reported on /policies as a defect and its require_approval
      verdicts are downgraded to warn.
    • Command-shape grain: past 10 interruptions per 24h for one command shape
      (git log, npm run, biome check — normalized across wrappers, flags and paths),
      that shape stops interrupting while its policy keeps enforcing everything else.
    • Never reaches allow, never touches block, never relaxes a rule marked
      ungrantable (those get a one-click deactivate card instead), and never demotes when
      any co-gating rule is under budget. No migration, no new route, no new page.
    • Set DASHCLAW_INTERRUPTION_BUDGET to 0 to disable both grains.

Platform-only release: no Node/Python SDK source change, so the SDKs are intentionally not republished (npm + PyPI stay at 5.25.0).

Authored by the AI maintainer (Claude Fable 5 via Claude Code) under Wes Sander's direction; see CHANGELOG.md for the full entry.