Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/target/
/dist/

# lefthook-generated hook scripts (machine-specific)
.hooks/

# Environment files (may contain secrets)
.env
.env.local
Expand Down
41 changes: 28 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ unit tests + builds. Clippy passing does not mean fmt passes; run both.
Run `just test` for integration tests if you touched `sprout-relay`,
`sprout-db`, or `sprout-auth` — these require a running Postgres and Redis.

**Pre-commit and pre-push hooks** are installed automatically by `just setup`.
Pre-commit runs 5 checks in parallel on every `git commit` (Rust fmt, Tauri Rust
fmt, desktop lint, web lint, mobile fmt) — a commit will fail if any are dirty.
Pre-push runs the full CI gate: all pre-commit checks plus clippy, unit tests,
desktop build, Tauri check, web build, and mobile tests (~minutes). Run
`just fmt-all` before committing to auto-fix all formatting in one shot. Run
`just hooks` to re-install hooks after env changes.

Additional rules:
- No `unsafe` code
- Do not introduce new `unwrap()` or `expect()` in production paths — use `?` and proper error types
Expand Down Expand Up @@ -110,11 +118,12 @@ first, then implement handling in the relay.
**Channel scoping**: Channels use `h` tags (NIP-29 group tag), not `e` tags.
Filters and queries must scope to `h` tags when operating within a channel.

**MCP tools — dual transport**: The MCP server in `sprout-mcp` uses two
patterns: write operations send signed Nostr events over WebSocket; read
operations call REST endpoints (see `relay_client.rs` for the HTTP helpers).
Add the REST endpoint or event handler first, then add the MCP tool that calls
it. Do not implement logic directly in MCP handlers.
**Agent-facing operations go in `sprout-cli`, not `sprout-mcp`**: `sprout-mcp`
is being phased out. New agent-facing features belong in `sprout-cli` — add a
subcommand there first, then wire the REST/WebSocket call in `client.rs`. Do
not add new tools to `sprout-mcp` unless specifically required for backward
compatibility. `sprout-dev-mcp` (shell + file tools for `sprout-agent`) is
separate and not being phased out.

**Workflow conditions**: `sprout-workflow` uses
[evalexpr](https://docs.rs/evalexpr) for condition evaluation. Keep expressions
Expand All @@ -129,13 +138,17 @@ check existing reply handlers for the pattern.
## Agent CLI (`sprout-cli`)

`sprout` is the agent-first CLI replacing `sprout-mcp`. Auth env vars
(`SPROUT_RELAY_URL`, `SPROUT_PRIVATE_KEY`) are auto-injected by the ACP
harness into managed agent subprocesses.
(`SPROUT_RELAY_URL`, `SPROUT_PRIVATE_KEY`, `SPROUT_AUTH_TAG`) are auto-injected
by the ACP harness into managed agent subprocesses.

All reads return sig-stripped JSON arrays; all writes return
`{event_id, accepted, message}`; creates add the entity ID. Exit codes:
0=ok, 1=input error, 3=auth missing. See `crates/sprout-cli/TESTING.md`
for the full live-testing runbook.
0=ok, 1=input error, 2=network/relay, 3=auth, 4=other, 5=write conflict (NIP-33 LWW).

`--format compact` is a **global** flag — it goes before the subcommand:
`sprout --format compact channels list`, NOT `sprout channels list --format compact`.

See `crates/sprout-cli/TESTING.md` for the full live-testing runbook.

---

Expand Down Expand Up @@ -166,8 +179,10 @@ See [TESTING.md](TESTING.md) for the full multi-agent E2E guide.

1. **Kind `39000` for channel metadata, not `41`** — kind 41 is NIP-01 (unused). All kinds defined in `sprout-core/src/kind.rs`.
2. **Relay queries must specify `kinds`** — omitting `kinds` triggers the p-gate (403). Always include explicit kind filters.
3. **Worktrees: `cd` in the same command** — shell CWD doesn't persist between tool calls. Use `cd /path && cargo build` as one command.
4. **Desktop fmt check fails in worktrees** — run `just desktop-tauri-fmt-check` from the main checkout. CI is unaffected.
3. **`messages search` must include `--kinds`** — an open-ended search (no kinds) hits the relay p-gate and returns 403. Pass at least `--kinds 9,45001,45003` to scope the query.
4. **Worktrees: `cd` in the same command** — shell CWD doesn't persist between tool calls. Use `cd /path && cargo build` as one command.
5. **Desktop crate excluded from root workspace** — `cargo test` at repo root does NOT run desktop tests. Use `cargo test --manifest-path desktop/src-tauri/Cargo.toml` explicitly.
6. **Desktop fmt check fails in worktrees and blocks commits** — the pre-commit hook runs `just desktop-tauri-fmt-check`, which fails in git worktrees because `cargo fmt` resolves workspace paths relative to the worktree root. Run `just desktop-tauri-fmt` from the main checkout to apply the fix, then re-stage and commit. CI is unaffected.

---

Expand Down Expand Up @@ -248,7 +263,7 @@ flutter analyze
flutter test
```

Or from repo root: `just mobile-check` and `just mobile-test`.
Or from repo root: `just mobile-fmt` (auto-fix), `just mobile-check` (lint + fmt check), `just mobile-test` (tests).

### Testing Conventions

Expand All @@ -263,7 +278,7 @@ Or from repo root: `just mobile-check` and `just mobile-test`.

## See Also

- [CONTRIBUTING.md](CONTRIBUTING.md) — setup, code style, PR process, how to add event kinds / MCP tools / API endpoints
- [CONTRIBUTING.md](CONTRIBUTING.md) — setup, code style, PR process, how to add event kinds / CLI subcommands / API endpoints
- [TESTING.md](TESTING.md) — multi-agent E2E test guide
- [ARCHITECTURE.md](ARCHITECTURE.md) — system design and component relationships
- [README.md](README.md) — project overview and quick start
12 changes: 12 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ default:
setup:
./scripts/dev-setup.sh

# Install git hooks via lefthook
hooks:
git config --local core.hooksPath .hooks
lefthook install --force

# ⚠️ Wipe ALL data and recreate a clean environment
[confirm("This will DELETE all local data. Continue? (y/N)")]
reset:
Expand Down Expand Up @@ -93,6 +98,9 @@ desktop-tauri-fmt:
desktop-tauri-fmt-check:
cargo fmt --manifest-path {{desktop_tauri_manifest}} --all -- --check

# Format all code (Rust + Tauri Rust + Dart)
fmt-all: fmt desktop-tauri-fmt mobile-fmt

# Ensure sidecar placeholder binaries exist (Tauri validates externalBin at compile time)
_ensure-sidecar-stubs:
#!/usr/bin/env bash
Expand Down Expand Up @@ -271,6 +279,10 @@ mobile_dir := "mobile"
mobile-install:
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter pub get

# Format all Dart code
mobile-fmt:
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && dart format .

# Run mobile lint and format checks
mobile-check:
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && dart format --output=none --set-exit-if-changed . && flutter analyze
Expand Down
1 change: 1 addition & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pre-commit:
parallel: true
commands:
rust-fmt:
run: just fmt-check
Expand Down
7 changes: 7 additions & 0 deletions scripts/dev-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,13 @@ else
warn "Web directory not found at ${WEB_DIR} — skipping."
fi

# ---- Install git hooks ------------------------------------------------------

log "Installing git hooks..."
git config --local core.hooksPath .hooks
lefthook install --force
success "Git hooks installed"

# ---- Print connection info --------------------------------------------------

echo ""
Expand Down