Managed Agent that tracks DIY/underground bands for tour dates and one-offs the aggregators miss.
Scene Radar demonstrates solid tool design with clear naming conventions (verb_noun pattern), comprehensive parameter schemas using Zod, and well-structured descriptions. All 14 tools are explicitly registered with input schemas and descriptions. However, output schemas are not formally documented, responses are shaped ad-hoc via helper functions (json(), bandRow(), showRow(), sourceRow()). Parameter descriptions are generally strong but some lack actionable constraints (e.g., 'sources' array in bands_update has no format guidance). Error handling returns structured messages but lacks recovery guidance or categorization. The tool composition is excellent, each tool has a single responsibility and outputs include IDs for chaining. Descriptions average ~150 chars, within the 10-1024 baseline, and all parameters have descriptions.
Full record for one band: canonical_url and identity, everything you learned last sweep, plus any notes or lineup qualifier the human attached. Start here rather than re-deriving a band from a name search.
THE ROSTER — read this FIRST on every sweep, before touching memory. It is the authoritative watchlist: who is on it, their tier, and whether they are due for a check. The human curates this; tiers and list membership can change between sweeps and those changes are binding. Defaults to the bands you should actually work (listed=active).
Add a band you discovered through a scene edge to the roster as a SUGGESTION for the human to triage. It lands with no tier and is not swept until they promote it, so suggesting costs nothing. Requires a hard edge — shared member, split, label, tourmates, comp, scene. Sonic similarity is NOT an edge and must never be used here. Re-suggesting a band already on the roster is a safe no-op, and a dismissed band is never resurrected.
Record what you learned about a band: identity, status, signal, sources, cadence. Call this for EVERY band you check, including ones where you found nothing — last_checked is how the roster knows the work happened. You cannot change tier or list membership here; those are the human's.
Output schemas not formally documented. Responses are shaped via helper functions (json(), bandRow(), showRow()) but the structure is not declared in tool definitions. LLMs cannot plan downstream calls without knowing what fields to expect.
Error handling returns structured messages but lacks recovery guidance. Errors like 'no band with slug' do not suggest next steps (e.g., 'Try bands_list() to find valid slugs'). Errors are not categorized as retryable, user-fixable, or fatal.
Parameter 'sources' in bands_update and shows_add is an array with no format guidance. Should specify: array of URLs? IDs? Objects? Current description is empty or minimal.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 70 | 2026-07-28+ | v2 |
Add or update a show on the board. Only push shows that pass the taste profile's ring rules for their tier. A CONFIRMED entry REQUIRES a source URL you actually fetched that states the date — if you don't have that, mark it SIGNAL and let the human decide.
Get the full record for one show by id, including sources, why_now, and any notes the human added.
List shows on the board, soonest first. Defaults to upcoming only. Call this BEFORE adding anything, so you can dedup against what's already there and find the id of a record you may need to supersede. A show whose status is anything but 'new' has already been triaged by the human — do not re-report it as a find.
Full record for one source by id.
List all sources. Defaults to adopted only — the ones actually in use. 'proposed' are waiting for the human to triage; 'rejected' are kept so the radar doesn't re-propose them.
Propose a new source for the human to adopt. It won't be used in sweeps until they approve it — a hallucinated venue is a hallucinated show. Requires a URL you can actually fetch.
Update a source's metadata: reach, notes, produced_finds. The agent can only touch these fields; tier and status are the human's.
Get the full record for one sweep by id, including the complete report.
List all sweep runs with their verdicts and stats. The report text is stripped from the list endpoint.
Save a finished sweep report. The sweep runner POSTs finished reports here so the history lives with everything else the sweep produced.
shows_add combines multiple concerns: create new show, update existing show (via 'id' param), and validate against taste profile. Consider splitting into shows_create and shows_update for clarity.
sweeps_save accepts optional 'ran_at' with default 'now' but no timezone guidance. ISO 8601 format is assumed but not stated. Could cause timestamp misinterpretation across regions.