SYMPHONY

Agentic reliability and security intelligence. Uncover hidden dependencies. Investigate failures. Expose vulnerabilities.

Inspiration

When a microservice goes down, the real cause is rarely where the dashboard points. Architecture diagrams show the dependencies someone remembered to document; outages follow the ones that actually exist. A payment service quietly calling an auth service is invisible until auth fails and payments fail with it.

Security has the same gap. A vulnerability advisory tells you a package is affected, but not which other services are exposed through it. Teams end up answering the same questions by hand: what broke, why, who else is affected, and does the fix really work?

We wanted a tool that answers those questions from evidence, and that says so plainly when it can't.

What it does

SYMPHONY watches a system of six services (Frontend, API Gateway, Payment, Catalog, Auth, Database), works out why something failed, and checks the system for known vulnerabilities. It runs in two modes:

  • Simulation mode (default). A built-in simulator lets you break the system on purpose with an Auth or Payment outage and watch the failure spread. It is repeatable, so it is ideal for demos and testing.
  • Real-services mode. SYMPHONY connects to real microservices running in Docker. It reads each service's health, logs, and request traces over HTTP, and investigates what is actually happening.

In both modes it provides:

  • Dependency graph. Shows the five documented dependencies. The graph supports hover tracing, a selected-service panel, drag to pan, and zoom. A dependency nobody documented appears only after the Investigator finds proof in the traces.
  • Investigator agent. An AI agent (Gemini) diagnoses the incident using three tools: service health, logs, and request traces. If traces show Payment calling Auth, it reports a new dependency, and the system accepts it only when the cited trace evidence supports it.
  • Vulnerability scanning. Each service has a list of packages with exact versions. SYMPHONY looks them up in the real OSV.dev advisory database. A failed lookup is shown as a failure, never as "zero findings."
  • Security Analyst agent. Explains which advisories matter and how serious they are, citing advisory IDs from the real scan. The rule-based impact and priority are shown beside it, so you can compare the two.
  • Recovery agent. Decides which service to repair and how (restart, rollback, or failover), citing the Investigator's evidence. In simulation mode, the simulator tests the choice on a copy of the system and reports whether things recovered. In real-services mode, SYMPHONY only recommends the action and marks it not_applied, because it never changes your real services; the next health check shows whether it worked.
  • Automation. One Run full assessment button investigates, scans all six services, and assesses each result. In real-services mode, SYMPHONY also checks health every 10 seconds and starts the same assessment when something changes. External monitoring tools can start it too, through a token-protected webhook. Repeated identical triggers are ignored so the AI isn't called needlessly.

Anything unfinished or failing says so. Nothing returns fake success.

What is not built yet

Service discovery. SYMPHONY does not find services on its own for now. The six services and their addresses are fixed in the configuration (by default localhost ports 8100–8105, changeable with environment variables). It can investigate those services in depth, but it cannot yet look at a running environment and work out which services exist.

How we built it

  • Jac 0.34.19 for the full stack: server operations, client dashboard, and agents in one language and one project.
  • byLLM with Gemini for the three agents. Each agent is limited to a few read-only tools and six reasoning steps, uses a fallback model, and reports explicit errors for authentication, quota, timeout, and malformed output.
  • A service provider layer. One setting (SYMPHONY_SERVICE_MODE) switches between the simulator and real Docker services. The rest of the app does not change.
  • A deterministic simulator that holds the true graph and the injected fault privately. Diagnostics, previews, and agent tools show symptoms only.
  • OSV.dev queried server-side, with timeouts, malformed-response handling, and separate completed, partial, and failed states.
  • Validation around every agent. Evidence must belong to the current run. Discovered dependencies need matching trace evidence. Repair and risk statements must cite real evidence or advisory IDs. Overstated claims such as "compromised" are rejected unless explicitly negated.
  • A Jac dashboard with panel-specific states, protection against stale responses, a light theme, and an interactive graph.
  • Tests that don't spend quota. Agent logic is tested with a mock model against the real simulator, so the suite runs without calling Gemini or OSV.

Challenges we ran into

  • Keeping the answer hidden. An investigator is only meaningful if it can't see the answer. Making sure no tool, log, preview, or serialization path leaks the injected fault or the true graph took deliberate design and tests.
  • Never faking success. It is tempting to let a failed scan show a clean result or a model summary stand as fact. We built the boundaries so a provider error, a stale run, or an unsupported claim becomes a visible failure.
  • Stale state. Resetting the simulation, or health changing, while an agent or request is in flight could attach old results to a new run. Run IDs and a request guard in the client fixed this.

Accomplishments that we're proud of

  • A system where every model claim is checked against evidence before it reaches the screen.
  • A hidden dependency that is discovered, not hard-coded in the UI, and saved so later impact analysis uses it.
  • AI-proposed recovery that is checked by simulation. The model chooses the repair; the simulator, not the model, reports whether it worked.
  • One app, two modes: a repeatable simulator for demos and real Docker services for live behavior, behind a single switch.
  • Automatic assessment from health polling and webhooks, with duplicate requests filtered out.
  • Honest security output: real advisories, unknown severity preserved, and an incomplete scan never presented as an all-clear.
  • Three agents that share the same guardrails: bounded steps, read-only tools, evidence-checked output, and explicit failures. The two newer agents each run in an isolated, per-request session so concurrent calls can't mix their results.

What we learned

  • Agents are far more trustworthy when a deterministic component has the last word. Letting the model propose and the system verify gave us useful AI behavior without blind trust.
  • Hiding information is a feature. Limiting what an agent can see forced it to reason from observations, which is what a real on-call engineer has to do.
  • Failure paths deserve as much design as success paths. Most of our validation code exists to say "no" clearly.
  • Testing agents with mock models makes them practical to iterate on and cheap to run.

What's next for Symphony

  • Automatic service discovery. Find the running services and their addresses (for example from Docker or an orchestrator) instead of using a fixed list of six. This also needs automatic graph layout so new services appear without hand-placed positions; pan and zoom are already in place.
  • Acting on recommendations. Let an operator approve a recommended repair and have SYMPHONY apply it, then confirm recovery from the next health check.
  • Richer repair actions and multi-step recovery plans, still verified before they are proposed.
  • Persistence and multi-user support. State is currently kept in a single server process.

Built With

Share this project:

Updates

Submission history