Commit Graph
79 Commits
Author SHA1 Message Date
npub1jmc9dt2lyvzu3h0kxlwxt5zg4fxp9476awyxw6gwxn72g6cw7exqs64whmandTyler Longwell acb01e4da0 feat(relay): wire conformance emitter into ingest seam
Add `crates/buzz-relay/src/conformance/` module:
- `Tracer` re-export, `NoopTracer` (production), `JsonlTracer` (test/CI).
- `EmitGuard::arm(tracer, state, kind) → (guard, counting_tracer)`:
  RAII coverage breach. The guard wraps the original tracer in a
  counting layer; production callers transparently use that wrapper.
  If no emit reaches the wrapper before the guard drops, the guard
  emits a synthetic `ImplBug` step on the underlying tracer — the
  checker treats that as CoverageBreach. The wrapper design means
  production paths never need to "disarm" or pass anything around;
  a future new exit that forgets to emit will be caught
  automatically.
- `state_for_request(tenant, actor)`: builds AbstractState. Pulls
  community + host directly from server-resolved TenantContext.
- `claimed_community_from_event`: reads the event's h tag for the
  trace's `claimed_community` field — recorded SEPARATELY from
  `resolved_community` so M2 (claim≠resolved) and M8 (host/channel
  disagreement) bite at the checker.
- `sanitized_reason_for(&IngestError) → SanitizedReason`: 1:1 map
  of IngestError variants (Rejected/AuthFailed/Internal) onto the
  closed SanitizedReason alphabet (Invalid/Restricted/ServerError).
  Adding a fourth IngestError variant breaks this match — CI catches
  it before it ships.

Emitter wiring in `crates/buzz-relay/src/handlers/ingest.rs`:
- `ingest_event` is now a thin wrapper: arms EmitGuard, calls
  `ingest_event_inner`, and on Err maps to SanitizedError. All 36
  early-Err returns and 6 Ok returns in the inner fn are covered
  by this single outer mapping.
- At `check_channel_membership` call site (line 1401): emits
  `AuthCheck { channel, claimed_community, verdict }` with
  Allow on Ok, Deny on Err. The verdict basis is `tenant.community()`
  server-resolved — confirmed at ingest.rs:424's `is_member_cached`
  call signature (not event-derived).
- At each `dispatch_persistent_event` call site (lines 1908, 2014):
  emits `WriteInsert` (channel + was_inserted=true), `WriteDuplicate`
  (channel + was_inserted=false), or `WriteInsertGlobal` (no channel).
  This is the entire write side of the ingest seam.

`crates/buzz-relay/src/handlers/event.rs` `dispatch_persistent_event`:
- No emit added. Documented why inline: the spec has no separate
  fan-out action — acceptance is recorded at ingest's WriteInsert;
  fan-out surfaces as ReadMessageRows on the subscriber side (the
  read seam in req.rs, lands in the held-back additive diff).

AppState carries `tracer: Arc<dyn buzz_conformance::Tracer>`,
defaulting to NoopTracer (zero cost). Test contexts overwrite this
field with a JsonlTracer after construction.

Verify:
- cargo check -p buzz-relay green
- cargo test -p buzz-relay --lib: 378/378 (no regressions)
- cargo test -p buzz-conformance: 9/9 (checker still bites all four
  failure modes)

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
2026-06-26 23:57:18 -04:00
npub1jmc9dt2lyvzu3h0kxlwxt5zg4fxp9476awyxw6gwxn72g6cw7exqs64whmandTyler Longwell e1b090e48e feat(conformance): runtime trace schema + independent replay checker
Adds `crates/buzz-conformance/` — the substrate for runtime formal-spec
conformance. It is the **independent oracle** for the multi-tenant relay:
given a trace of seam events recorded by the relay at runtime, the
checker asserts they obey `docs/spec/MultiTenantRelay.tla`. Production
binaries pay zero cost (the relay defaults to `NoopTracer`); test/staging
runs against `JsonlTracer` and the checker re-runs every captured trace.

Crate contents:

- `src/lib.rs` — schema: `TraceStep`, `TraceAction` (8 spec actions +
  `ImplBug` for coverage-breach), `AbstractState` (resolved_community,
  bound_host, actor), the `Tracer` trait, `NoopTracer` for prod.
- `src/transitions.rs` — re-implementation of the spec's `Next` relation
  in Rust, used by the checker. Owned by this crate, not pulled from the
  relay — that's what makes the oracle independent.
- `src/checker.rs` — replay engine: `check_trace` returns
  `Err(IllegalTransition | StateMismatch | NonInterference | CoverageBreach)`
  on any departure from the spec. 9 unit tests covering each failure mode
  plus the M2/M8 (`claimed != resolved`) and NI/ReadConfinement bites.
- `tests/replay_fixtures.rs` + `tests/fixtures/*.jsonl` — five tests that
  reconstruct three on-disk JSONL fixtures from typed Rust, assert the
  committed file matches byte-for-byte (any schema change requires
  `BUZZ_CONFORMANCE_UPDATE=1` to refresh), then replay each through
  `check_trace`:
    - `good.jsonl`                       → `Ok(())`
    - `bad_host_channel_mismatch.jsonl`  → `IllegalTransition`
    - `bad_coverage_breach.jsonl`        → `CoverageBreach`
- `TRACE_SCHEMA.md` — grounds every action in its `MultiTenantRelay.tla`
  line and calls out the three load-bearing projection rules.
- `LIMITS.md` — honestly describes what a green run does/doesn't prove,
  and the CI command listing the test surfaces.

Production-fence discipline: deps are exactly `serde / serde_json /
thiserror / uuid`. Zero `buzz-*` production crates. `CommunityLabel(Uuid)`
is a newtype in this crate, NOT `buzz_core::CommunityId` — the checker
physically cannot inherit a production bug because it shares no code
with the relay.

Verify discipline:
- `cargo test -p buzz-conformance --lib`             → 9/9
- `cargo test -p buzz-conformance --test replay_fixtures` → 5/5
- Mutate→red→restore proven three times (in earlier session): row-label
  corruption → `NonInterference` fires; trace `claimed = resolved` →
  `IllegalTransition` vanishes; counter threshold loosened →
  `ImplBug` doesn't fire.

This commit lands the substrate only. The relay-side glue
(`crates/buzz-relay/src/conformance/{mod,tracers}.rs`, `AppState.tracer`,
`EmitGuard`) and the ingest-seam emitter follow on the next branch
(`quinn/conformance-relay-glue`). The req.rs read-seam emitters land
after.

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
2026-06-26 23:56:25 -04:00
tlongwell-blockandEva a8a9dd9e1a feat(relay): wire relay + admin call sites to community-scoped v3 API
Threads server-resolved `community_id`/`TenantContext` through the whole
relay call graph and the operator CLI against the v3 DB/pubsub API, so
every scoped row read and every Redis publish names a community the relay
derived from data, never from caller input.

Relay (`crates/buzz-relay`):
- Read-path caches take `CommunityId`; write/invalidate publishers take
  `&TenantContext` (the Redis topic key needs the host). The cross-node
  fan-out path only has the community, so caches stay constructible there.
- Doors fail closed: WS/bridge/media/NIP-05 bind community from the request
  host via `bind_community`, falling through to an empty/404 response on an
  unmapped host — no default tenant, no host echo.
- Background loops get tenant from the DB row they act on: the reaper builds
  `TenantContext::resolved(row.community_id, row.host)` per archived channel
  from the reaper RETURNING; the dev/CI reconciler and reminder scheduler
  resolve the one configured community from `relay_url`, fail-closed.
- Deployment-community cases with no connection tenant (git hook/finalize,
  workflow sink) resolve via the same host-resolution seam.
- Drop the Typesense-only `reindex_kind0` backfill binary, obsolete under
  the Postgres FTS migration and referenced nowhere.

Admin CLI (`crates/buzz-admin`):
- New `resolve_admin_tenant` reads `RELAY_URL` host (the CLI runs
  `compose exec relay buzz-admin`, sharing the relay's env) and resolves it
  via `lookup_community_by_host`, fail-closed on an unmapped host.
- Scope the NIP-43 membership-list publish (`EventTopic::Global`), channel
  reconcile, `get_members`, and the kind:39000 existence `EventQuery`
  (`..EventQuery::for_community`). Drop the now-dead `uuid` dep.

Workspace gate: `cargo check --workspace` green; buzz-db 97/97, buzz-audit
13/13, buzz-relay 375 + main 1 (`--include-ignored --test-threads=1`),
buzz-admin compiles, fmt + buzz-admin clippy clean.

Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-06-26 20:37:00 -04:00
tlongwell-blockandQuinn c2477ba34f rewrite(search): Postgres FTS, community-scoped, drop Typesense
The Lane-0 freeze landed `events.search_tsv TSVECTOR GENERATED ALWAYS AS
(to_tsvector('simple', content)) STORED` + `GIN (search_tsv)` directly in
the schema. With that in place the entire Typesense apparatus is dead
weight: there is nothing to index out-of-band, no consistency window to
reason about, no client-forgeable index/content drift. Indexing is the
SQL write.

This rewrites `crates/buzz-search/` from scratch around that:

  - `query.rs`: one SQL builder. `community_id = $ctx` is the first
    predicate of every executed statement and is unconditional —
    `SearchQuery` requires a `CommunityId` at the type level (no
    construction path omits it). `search_tsv @@ websearch_to_tsquery(...)`
    is the FTS predicate; `ts_rank_cd DESC, created_at DESC, id` is the
    order. Channel scope replaces today's `__global__` sentinel with
    `channel_id IS NULL`. Empty query short-circuits without a roundtrip.

  - `lib.rs`: thin `SearchService { pool }`. Takes `&PgPool` directly so
    the crate stays a leaf — no buzz-db dependency. Re-exports
    `CommunityId` for callers that need to mint the fence.

  - `error.rs`: collapsed to one variant (`Db(sqlx::Error)`); empty
    queries are not errors.

  - Deleted `collection.rs` and `index.rs` (Typesense HTTP client and
    indexer). Dropped `reqwest`/`serde`/`serde_json`/`chrono`/`nostr`
    from `Cargo.toml`.

  - Added `tests/fts_integration.rs` — 8 integration tests against real
    Postgres, each on its own throwaway schema applying the frozen
    `migrations/0001_initial_schema.sql` via `include_str!`. The
    load-bearing one is `search_does_not_return_other_community_events`:
    mutating the `community_id = $ctx` predicate to `1=1` makes that
    test go red (verified, then reverted) — the fence bites where it
    has to.

Conformance row 50 — search re-auth and one-shot NIP-50 — is unchanged
in shape: the relay refetches canonical events per hit through buzz-db's
scoped fetcher and runs the access predicate. Search is never the
access boundary; this crate just returns candidate ids. The row's
Typesense prose rewrite is owned by Eva's integration lane (one writer
per path).

EXPLAIN ANALYZE evidence on a 200k-row community confirms the planner
picks `Bitmap Index Scan on events_p<...>_search_tsv_idx` for the
populated partition (full plan in RESEARCH/SEARCH_LANE_FTS_EXPLAIN.md
in the workspace). Single-column `GIN (search_tsv)` is sufficient at
this scale — no `btree_gin` needed (Max's caveat holds).

Cross-lane removals owed to Eva (relay-wiring lane, not this commit):
  - relay state.rs: remove `search_index_tx` mpsc + worker
  - relay main.rs: remove `search.ensure_collection()` call
  - relay handlers/event.rs: remove `search_index_tx.send()`
  - relay api/bridge.rs::handle_bridge_search: rewrite to new API
  - relay handlers/req.rs::handle_search_req: rewrite to new API
  - relay handlers/req.rs::build_search_channel_scope_filter: delete
  - relay bin/reindex_kind0.rs: delete
  - docker-compose.yml: drop typesense service + volume
  - docs/multi-tenant-conformance.md row 50: rewrite Typesense prose

Tests: `cargo test -p buzz-search --test fts_integration --
--include-ignored --test-threads=1` — 8 passed, 0 failed.
Clippy: `cargo clippy -p buzz-search --all-targets -- -D warnings` — clean.

(cherry picked from commit e31c098ce5)

Co-authored-by: Quinn <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-06-26 20:36:58 -04:00
Will PflegerandGitHub 68a0cc8506 chore(release): release Buzz Relay version 0.1.1 (#1269) 2026-06-24 23:49:09 -04:00
0cee0435f7 feat(relay): add buzz-admin member management CLI with NIP-43 roster publish (#1265)
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
2026-06-24 23:13:31 -04:00
4d2eb52a6c fix(buzz-dev-mcp): resolve non-WSL bash so the MCP shell works on Windows (#1119)
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
2026-06-18 19:33:35 -04:00
d99ad131f1 refactor: rename sprout backend to buzz (#958)
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger96@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1fgdl5qqnh3k3f2xkqrvt7cujalhm623x4s7fdjdj5yrtp5fzjl9qrjpucw <4a1bfa0013bc6d14a8d600d8bf6392efefbd2a26ac3c96c9b2a106b0d12297ca@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Will Pfleger <wpfleger96@gmail.com>
2026-06-10 19:29:51 -04:00
421593062f mesh: Rust-owned coordinator — fix saved-agent reconnect flakiness + DRY the start path (#879)
Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
2026-06-09 10:59:28 -04:00
Will PflegerandGitHub ef98ae942a fix(cli): publish ephemeral events over WebSocket via sprout-ws-client (#876) 2026-06-05 16:26:30 -04:00
Will PflegerandGitHub f1c672fea5 chore: deprecate sprout-mcp — fill CLI gaps, remove crate and all references (#850) 2026-06-05 12:31:52 -04:00
33cfc85293 Mesh-LLM v1: relay-gated direct-iroh inference between users (WAN) (#822)
Signed-off-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Max <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
2026-06-03 10:49:09 -04:00
tlongwell-blockandGitHub ede8ddb425 Sprout × mesh-llm: in-process mesh node (serve/consume) + relay admission (#798) 2026-06-02 10:28:20 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Will PflegerWill Pfleger
efa93c4383 chore(deps): update rust crate sqlx to 0.9 (#740)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Will Pfleger <wpfleger@block.xyz>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
2026-05-25 21:32:34 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Will Pfleger
e5c35bb59e chore(deps): update rust crate serde_json to v1.0.150 (#737)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
2026-05-23 23:53:59 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
4278eb5202 fix(deps): update rust crate similar to v3 (#690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 03:19:20 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0de910f14d fix(deps): update rust crate toml to v1 (#691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-22 21:45:59 -04:00
Will PflegerandGitHub a65b7fc06f fix(deps): migrate nostr crate from 0.36 to 0.44 (#708) 2026-05-22 17:17:11 -04:00
8bc94413eb feat(relay/git): git on Sprout, S3-backed (#726)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@users.noreply.sprout>
Co-authored-by: Sami <sami@users.noreply.sprout>
Co-authored-by: Quinn <quinn@users.noreply.sprout>
Co-authored-by: Mari <95cae996907d7cab9f5dbf43c0f53edeac6ab0b032a6feae4abfd784e467b3f5@users.noreply.sprout>
Co-authored-by: Eva <eva@users.noreply.sprout>
Co-authored-by: Tyler Longwell <tyler@block.xyz>
2026-05-22 15:05:07 -04:00
Will PflegerandGitHub d0d2670fe2 fix(deps): upgrade redis 1.0 and deadpool-redis 0.23 together (#703) 2026-05-21 17:55:44 -04:00
Will PflegerandGitHub d4f55cee3c fix(deps): upgrade getrandom to 0.4 with fill() rename (#704) 2026-05-21 17:40:18 -04:00
tlongwell-blockandGitHub 962dd7dced feat(sprout-agent): auto-fallback to Databricks OAuth (#699)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
2026-05-21 13:05:58 -04:00
fa9e26fa5c feat(sprout-agent): Databricks provider with OAuth 2.0 PKCE auth (#698)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn (sprout agent) <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-21 12:08:24 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e08a971abf chore(deps): update rust crate dashmap to v6.2.1 (#652)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-20 23:09:12 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9df214d43a chore(deps): update rust crate tower-http to v0.6.11 (#647)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-20 23:08:56 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0dd9a05948 fix(deps): update rust crate sha2 to 0.11 (#665)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-20 22:54:25 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
881ed204bb chore(deps): update rust crate metrics to v0.24.6 (#638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-20 22:47:35 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9f4adcc74c chore(deps): update rust crate rmcp to v1.7.0 (#656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-20 22:39:39 +00:00
c9dd97ba1a feat(cli/mem): add mem patch, mem hash, and reject empty-stdin in mem set (#627)
Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Dawn (sprout agent) <c6237ef84fa537c78dcee78efd2d4e59f728859c7f194da42ac51ededfa0be05@sprout-oss.stage.blox.sqprod.co>
2026-05-20 14:51:30 -04:00
tlongwell-blockandGitHub 24520aa2b1 NIP-AE: agent engrams (kind:30174) — core memory injection + sprout mem CLI (#593)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Signed-off-by: Tyler Longwell <109685178+tlongwell-block@users.noreply.github.com>
2026-05-19 13:16:37 -04:00
tlongwell-blockandGitHub 70cb53e2c7 Add Sprig all-in-one agent binary (#605)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
2026-05-17 13:31:58 -04:00
tlongwell-blockandGitHub 92c859043c dev-mcp: add view_image tool (#602)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
2026-05-15 16:21:16 -04:00
WesandGitHub 1d604e8b2e Update Rust dependencies for pair relay (#534) 2026-05-11 10:47:22 -07:00
tlongwell-blockandGitHub 70a691517b feat: automatic git auth and signing for sprout agents (#528) 2026-05-11 10:38:45 -04:00
tlongwell-blockandGitHub 91f16e326f feat: embed sprout CLI in dev-mcp, add NIP-OA auth tag support (#525) 2026-05-11 06:57:34 -04:00
tlongwell-blockandGitHub 082414bf3f feat: sprout-agent + sprout-dev-mcp — minimal ACP coding agent (#493) 2026-05-10 22:33:58 -04:00
Bradley AxenandGitHub c6da3a72ab Add countdown bot reference example (#516) 2026-05-08 15:39:40 -07:00
3a12369491 feat: serve web UI from relay + repos page redesign (#479)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 19:20:13 +00:00
tlongwell-blockandGitHub 454781caae Sprout speaks Nostr. Nothing else. (#475) 2026-05-05 12:03:06 -04:00
tlongwell-blockandGitHub df33818b5b feat(relay): NIP-OA agent authentication for NIP-43 membership (WS + REST + git) (#471) 2026-05-04 12:12:22 -04:00
tlongwell-blockandGitHub 15bd9ba2ac feat: sprout-pair-relay — ephemeral sidecar for NIP-AB device pairing (#467) 2026-05-03 21:07:36 -04:00
tlongwell-blockandGitHub 1feb18e2e0 feat(git-sign-nostr): implement NIP-GS git object signing with Nostr keys (#459) 2026-05-03 10:05:30 -04:00
3899ca566d feat(git): Role-based push permissions with service-bound auth (#441)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
2026-05-01 00:25:33 -04:00
f23560d3d4 feat: Image & video uploads for MCP and CLI (Blossom protocol) (#433)
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
2026-04-30 14:35:02 -04:00
fcec10547d Route ACP observer traffic over relay (#421)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
Co-authored-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Co-authored-by: Tyler Longwell <tlongwell@squareup.com>
2026-04-30 09:34:37 -04:00
tlongwell-blockandGitHub 121737f93f NIP-34 git transport: Smart HTTP hosting with NIP-98 auth (#419)
Signed-off-by: Tyler Longwell <tlongwell@squareup.com>
2026-04-29 18:04:59 -04:00
Bradley AxenandGitHub 7c2c556d72 feat: Add local ACP session observer (#412) 2026-04-29 04:21:58 +00:00
e2c94a8538 feat(mobile): image upload + media viewer parity with desktop (#384)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 11:54:29 -07:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
12afa16cb1 chore(deps): update rust crate axum to v0.8.9 (#365)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-20 06:28:22 -07:00
tlongwell-blockandGitHub b8d6a5cf8b feat: NIP-AB device pairing — Phase 1 (core library + CLI) (#333) 2026-04-16 14:56:36 -04:00