Skip to content

Commit af1a30b

Browse files
committed
Merge remote-tracking branch 'origin/main' into benchmark/harness-accounting-and-solo
* origin/main: (48 commits) fix(hooks): scope pre-push lanes to branch merge-base diff (#6423) Enforce a three-day dependency cooldown (#6426) perf(desktop): resolve references without directory scans (#6328) feat(llm): stamp thinking effort on call-completed log line (#6424) Fix cross-owner relay agent mentions in owner-only builds (#6338) feat(cli): accept Buzz message links for thread reads (#6359) feat(workflows): add workflow editor (#6248) fix(desktop): preserve huddle speech boundaries (#6397) test(desktop): use a wordlist-safe separator in passphrase word-count test (#6356) fix(models): curate Databricks alias-aware labels for 5 missing endpoints (#6360) fix(acp): guard against unrequested public relay skills (#6394) feat(desktop): refine context-aware Projects collaboration (#6396) fix(desktop): distinguish duplicate agent devices (#6337) feat(desktop): close Buzz window with Cmd+W (#6314) refactor(prompt): simplify Buzz agent guidance (#6340) feat(desktop): make Projects workspaces selectable (#6368) Add Buzz-native collaboration benchmarks (#6264) Polish mobile timeline and emoji interactions (#6297) feat(desktop): make the Projects overview follow the selected section (#6335) refactor(desktop): coordinate TTS playback (#6341) ... Signed-off-by: Atish Patel <atishpatel2012@gmail.com>
2 parents a0f6211 + cd0d33f commit af1a30b

693 files changed

Lines changed: 71648 additions & 16275 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/benchmark-harbor.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ on:
55
branches: [main]
66
paths:
77
- "benchmarks/harbor-buzz-orchestra/**"
8+
- "benchmarks/buzz-dataset/**"
89
- ".github/workflows/benchmark-harbor.yml"
910
pull_request:
1011
paths:
1112
- "benchmarks/harbor-buzz-orchestra/**"
13+
- "benchmarks/buzz-dataset/**"
1214
- ".github/workflows/benchmark-harbor.yml"
1315

1416
permissions:
@@ -31,6 +33,9 @@ jobs:
3133
python -m pip install --disable-pip-version-check -e ".[dev]"
3234
pytest -q
3335
ruff check .
36+
# The task verifiers live in the sibling benchmarks/buzz-dataset, so
37+
# they need the harness config passed explicitly to stay linted.
38+
ruff check --config pyproject.toml ../buzz-dataset
3439
- name: Test provisioner
3540
working-directory: benchmarks/harbor-buzz-orchestra/testbed
3641
run: |

AGENTS.md

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,22 @@ clippy (workspace + Tauri), desktop TypeScript typechecking (`tsc --noEmit`),
125125
and fast unit tests in parallel (Rust, desktop JS, Tauri Rust, mobile Flutter)
126126
— no overlap with pre-commit. Builds are CI-only. Run `just fix-all` to auto-fix
127127
all formatting in one shot. Run `just ci` for the full local gate. Run `just
128-
hooks` to re-install hooks after env changes. Before agents run Git or hooks,
129-
activate the repo's Hermit environment (`. ./bin/activate-hermit`); do not
130-
rewrite hook commands to compensate for an unconfigured shell `PATH`.
128+
hooks` to re-install hooks after env changes. Each globbed pre-push lane is
129+
scoped to the branch's merge-base diff against `origin/main` (`git diff
130+
origin/main...HEAD`), matching CI's paths-filter — so a lane only fires when this
131+
branch actually changed a file it covers, never because `origin/main` moved.
132+
These lanes validate the checked-out HEAD; pushing a non-HEAD ref (explicit
133+
refspec, `--all`) gets a non-fatal `push-head-scope` warning and relies on CI for
134+
its path-scoped checks.
135+
Before agents run Git or hooks, activate the repo's Hermit environment
136+
(`. ./bin/activate-hermit`) so `./bin` leads `PATH` and the pinned toolchain
137+
(flutter, dart, lefthook) wins over any Homebrew version; do not
138+
rewrite hook commands to compensate for an unconfigured shell `PATH`. The
139+
pre-push hook self-pins regardless: `bin/.lefthookrc` (sourced by the generated
140+
`.git/hooks/*`) prepends the Hermit `bin/` to `PATH` and pins `LEFTHOOK_BIN`, so
141+
lane subprocesses resolve the pinned flutter/dart/lefthook even when an
142+
unactivated shell has Homebrew first. Activating Hermit remains recommended for
143+
non-hook commands.
131144

132145
**Commit with `git commit -s`.** The required **DCO Check** fails any PR with a commit missing a `Signed-off-by` trailer, and `just hooks` installs a `commit-msg` hook that adds it to commits you create locally (`git rebase` and `git cherry-pick` still need `--signoff`) — if you build commit commands programmatically, include `-s` every time. To repair a branch that already has unsigned commits: `git rebase --signoff main`, then force-push.
133146

@@ -202,15 +215,16 @@ or invoke with the full path.
202215
### Deep Links
203216

204217
`buzz://message?channel=<uuid>&id=<hex>` links reference a specific message
205-
thread. To read the linked thread:
218+
thread. Pass the link directly to the CLI:
206219

207220
```bash
208-
buzz --format compact messages thread --channel <uuid> --event <hex>
221+
buzz --format compact messages thread --link '<buzz://message?...>'
209222
```
210223

211-
Extract `channel` and `id` from the URL query parameters. The optional
212-
`thread` parameter (root event ID) can be ignored — `messages thread` resolves
213-
the full thread from the event ID alone.
224+
The selected message ID is authoritative: `messages thread` verifies its
225+
channel and derives its containing root. An optional `thread` parameter is
226+
accepted only when it matches that derived root. The explicit
227+
`--channel <uuid> --event <hex>` form remains available.
214228

215229
All reads return sig-stripped JSON arrays; all writes return
216230
`{event_id, accepted, message}`; creates add the entity ID. Exit codes:
@@ -476,11 +490,18 @@ are frozen.**
476490
So for any readable text, reach for rem-based Tailwind tokens, never arbitrary
477491
px:
478492

479-
- ✅ Stock rem tokens (`text-base`, `text-sm`, `text-xs`, …). **Chat body/author
480-
text === `text-base` (16px) — chat is the app's base type size**, and the
481-
surrounding timeline elements (timestamps, system rows, code, reactions) are
482-
deliberate steps on that same stock ramp.
483-
- ✅ The `text-2xs` (0.6875rem / 11px) and `text-3xs` (0.5rem / 8px) meta-text
493+
- ✅ Stock rem tokens (`text-base`, `text-sm`, `text-xs`, …) for general
494+
interface text. All of these derive from the virtual typography rem and
495+
therefore follow the user's font-size preference and Cmd +/- zoom.
496+
- ✅ Conversation text uses the named `text-message` token. Its
497+
**Smaller / Default / Larger contract is 13 / 14 / 15px** before keyboard
498+
zoom. Author names use the same conversation-size step; timestamps, system
499+
rows, code, and reactions are deliberate neighboring steps on the shared
500+
virtual-rem ramp. Keep those relationships tokenized rather than restoring a
501+
fixed 16px chat baseline or hardcoding preference-specific values in
502+
components.
503+
- ✅ The `text-2xs` (0.6875rem / 11px at a 16px virtual rem) and `text-3xs`
504+
(0.5rem / 8px at a 16px virtual rem) meta-text
484505
tokens (in `desktop/tailwind.config.js` under `theme.extend.fontSize`) for the
485506
sub-`text-xs` ramp — timestamps, count badges, tracking labels, tiny glyphs.
486507
These replaced the dozens of arbitrary `text-[…rem]` literals that had drifted

Justfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,31 @@ benchmark *ARGS:
996996
uv run --project benchmarks/harbor-buzz-orchestra/testbed \
997997
benchmarks/harbor-buzz-orchestra/scripts/benchmark.py {{ARGS}}
998998
999+
# Run the benchmark adapter + testbed gate exactly as CI does (pytest + ruff, pinned ruff from pyproject)
1000+
benchmark-check:
1001+
#!/usr/bin/env bash
1002+
set -euo pipefail
1003+
cd "{{justfile_directory()}}/benchmarks/harbor-buzz-orchestra"
1004+
# CI installs the dev extra with pip, so pyproject — not uv.lock — decides
1005+
# which ruff lints. Read the pin from there so this recipe cannot drift
1006+
# from the workflow (a floating specifier once meant CI failed on RUF100
1007+
# while the locked local ruff passed).
1008+
ruff_pin="$(grep -oE 'ruff==[0-9.]+' pyproject.toml | head -1 | cut -d= -f3)"
1009+
for project in . testbed; do
1010+
(
1011+
cd "$project"
1012+
echo "── harbor-buzz-orchestra/$project (ruff $ruff_pin)"
1013+
uv run --frozen pytest -q
1014+
uvx "ruff@$ruff_pin" check .
1015+
uvx "ruff@$ruff_pin" format --check .
1016+
)
1017+
done
1018+
# The task verifiers live in the sibling benchmarks/buzz-dataset, so they
1019+
# need the harness config passed explicitly to stay linted.
1020+
echo "── buzz-dataset (ruff $ruff_pin)"
1021+
uvx "ruff@$ruff_pin" check --config pyproject.toml ../buzz-dataset
1022+
uvx "ruff@$ruff_pin" format --check --config pyproject.toml ../buzz-dataset
1023+
9991024
# Stop the benchmark Docker stack (state and channels are kept)
10001025
benchmark-down:
10011026
docker compose --project-name buzz-benchmark down

benchmarks/buzz-dataset/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# buzz-dataset
2+
3+
Harbor tasks that score **Buzz product behavior**, not just task correctness.
4+
Each task poses an ordinary-looking question; what is graded is how the agent
5+
answers it through Buzz — where the reply lands, who it notifies, what it was
6+
willing to read.
7+
8+
| Task | Behavior under test |
9+
| --- | --- |
10+
| [`reply-to-thread`](reply-to-thread) | Answers in the user's thread instead of as a new top-level message |
11+
| [`user-mention`](user-mention) | Hands the turn back with an event-level `p`-tag mention of the requesting human |
12+
| [`read-named-path-outside-workspace`](read-named-path-outside-workspace) | Reads a path the user named explicitly instead of refusing it as out of bounds |
13+
| [`create-channel-invite-users`](create-channel-invite-users) | Creates a channel with the exact shape, TTL, and membership asked for |
14+
15+
For `reply-to-thread` and `user-mention` the graded behavior is **deliberately
16+
absent from `instruction.md`** — it has to come from `buzz-acp`'s production
17+
base prompt. Read a task's own `README.md` before editing its instruction or
18+
verifier.
19+
20+
## Running
21+
22+
These tasks need the [`harbor-buzz-orchestra`](../harbor-buzz-orchestra)
23+
harness, which launches the real `buzz-acp``buzz-agent``buzz-dev-mcp`
24+
stack inside the task container and exports the relay snapshot each verifier
25+
grades. Plain `harbor run` against this directory will not work, and neither
26+
will `harbor run -a oracle` (no `solution/solve.sh` is shipped — the Oracle
27+
agent replaces the Buzz agent, so no relay trial is provisioned).
28+
29+
From the repo root:
30+
31+
```bash
32+
just benchmark \
33+
--path benchmarks/buzz-dataset/reply-to-thread \
34+
--attempts 1 \
35+
--manifest benchmarks/harbor-buzz-orchestra/manifests/buzz-native-solo-luna.yaml \
36+
--endpoint-config benchmarks/harbor-buzz-orchestra/testbed/endpoints/openai-live.json \
37+
--n-concurrent 1
38+
```
39+
40+
Pass `--path benchmarks/buzz-dataset` to run the whole suite. The default
41+
condition is one solo agent on `gpt-5.6-luna` at `thinking_effort: medium`,
42+
which needs `OPENAI_COMPAT_API_KEY`; see
43+
[the harness README](../harbor-buzz-orchestra/README.md#buzz-native-tasks) for
44+
the alternative Sonnet condition and the evidence-snapshot contract.
45+
46+
The verifiers are covered by fixture tests that live with the harness, in
47+
`../harbor-buzz-orchestra/tests/`.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# create-channel-invite-users
2+
3+
## What the agent does
4+
5+
Creates a temporary private stream channel named `fix-pr-1234` with a one-hour
6+
lifetime and invites an exact subset of a seeded directory: three named users as
7+
members and two named bots with the `bot` role
8+
([instruction.md](instruction.md)).
9+
10+
Unlike the other tasks in this suite, the graded behavior **is** stated in the
11+
instruction. What makes it hard is precision at scale: the provisioner seeds 50
12+
users (`benchmark-user-01``50`) and 10 bots (`benchmark-bot-01``10`), so the
13+
agent has to resolve five specific names out of sixty look-alikes and invite
14+
nobody else.
15+
16+
## Environment
17+
18+
`python:3.12-slim-bookworm`, no extra packages: the agent never runs in this
19+
container's shell. `BuzzOrchestraAgent` launches the real `buzz-acp` /
20+
`buzz-agent` stack against a dedicated relay, and the agent does all its work
21+
through `buzz channels create` / `channels invite`. Agent timeout 300s.
22+
23+
Directory identities are derived deterministically from the owner key
24+
(`BuzzTrialProvisioner._stable_credential`) without persisting any secret, and
25+
`_seed_directory` skips profiles already published — so reruns are idempotent
26+
and pubkeys are stable across trials.
27+
28+
## Verifier
29+
30+
Reads the post-agent `/logs/artifacts/buzz-evidence.json` snapshot. The
31+
snapshot's `observed_channels` come from the production CLI
32+
(`channels search --exact --include-archived` plus `channels members`), so the
33+
verifier grades the same view a user would see. Every dimension is
34+
programmatic; `reward` is the conjunction of all of them.
35+
36+
| Dimension | Type | Measures |
37+
| --- | --- | --- |
38+
| `evidence_complete` | programmatic | Snapshot is v1, names this task, and carries all 60 directory rows (50 users + 10 bots), the 5 resolvable targets, and exactly one orchestrator. Harness health, not agent skill — a 0 here means the provisioner or relay is suspect |
39+
| `channel_created` | programmatic | Exactly one channel named `fix-pr-1234` exists |
40+
| `channel_shape` | programmatic | `channel_type = stream`, `visibility = private`, not archived |
41+
| `temporary_channel` | programmatic | `ttl_seconds == 3600` — "for one hour", read from the kind:39000 `ttl` tag surfaced by `channels search` |
42+
| `exact_membership` | programmatic | Member pubkeys are exactly the owner plus the 5 targets — no extras, no duplicates |
43+
| `expected_roles` | programmatic | The 3 users hold `member`, the 2 bots hold `bot`, the creator holds `owner` |
44+
45+
## Layout
46+
47+
```
48+
create-channel-invite-users/
49+
├── instruction.md # Prompt posted to the agent as the trial user
50+
├── task.toml # Metadata, timeouts, 1 CPU / 1 GiB environment
51+
├── environment/Dockerfile # Bare python image; the relay stack is uploaded
52+
└── tests/
53+
├── test.sh # Runs verify.py against the evidence snapshot
54+
└── verify.py # Deterministic scorer (see table above)
55+
```
56+
57+
To change the target set, edit `task_fixtures.TARGET_USERS` / `TARGET_BOTS`,
58+
`instruction.md`, and the matching constants at the top of `tests/verify.py`
59+
all three must agree, and `evidence_complete` will fail loudly if the directory
60+
size drifts from 60.
61+
62+
## Running
63+
64+
```bash
65+
just benchmark \
66+
--path benchmarks/buzz-dataset/create-channel-invite-users \
67+
--attempts 1 \
68+
--manifest benchmarks/harbor-buzz-orchestra/manifests/buzz-native-solo-luna.yaml \
69+
--endpoint-config benchmarks/harbor-buzz-orchestra/testbed/endpoints/openai-live.json \
70+
--n-concurrent 1
71+
```
72+
73+
`harbor run -a oracle` does **not** work here, and no `solution/solve.sh` is
74+
shipped: the Oracle agent replaces `BuzzOrchestraAgent`, so no relay trial is
75+
provisioned and no evidence snapshot is exported. The verifier is covered
76+
instead by fixture tests in
77+
`../harbor-buzz-orchestra/tests/test_create_channel_invite_users_verifier.py`.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM python:3.12-slim-bookworm
2+
3+
WORKDIR /app
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Create a temporary private stream channel named `fix-pr-1234` for one hour.
2+
3+
Invite these users as members:
4+
5+
- `benchmark-user-07`
6+
- `benchmark-user-19`
7+
- `benchmark-user-42`
8+
9+
Invite these bots with the bot role:
10+
11+
- `benchmark-bot-03`
12+
- `benchmark-bot-08`
13+
14+
Do not invite any other users or bots. When finished, reply briefly with what
15+
you created.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
schema_version = "1.3"
2+
3+
[task]
4+
name = "buzz-native/create-channel-invite-users"
5+
description = "Create a temporary PR channel with an exact subset of users and bots."
6+
authors = [{ name = "Buzz" }]
7+
keywords = ["buzz-native", "channels", "membership", "cli"]
8+
9+
[metadata]
10+
difficulty = "medium"
11+
category = "collaboration"
12+
tags = ["channels", "membership", "cli"]
13+
14+
[agent]
15+
timeout_sec = 300.0
16+
17+
[verifier]
18+
timeout_sec = 30.0
19+
20+
[environment]
21+
network_mode = "public"
22+
cpus = 1
23+
memory_mb = 1024
24+
storage_mb = 1024
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
python3 /tests/verify.py \
5+
--evidence /logs/artifacts/buzz-evidence.json \
6+
--reward /logs/verifier/reward.json \
7+
--details /logs/verifier/details.json

0 commit comments

Comments
 (0)