comment-analyzer
Use this agent when you need to analyze code comments for accuracy, completeness, and long-term maintainability. This includes: (1) After generating large documentation comments or docstrings, (2) Before finalizing a pull request that adds or modifies comments, (3) When reviewing existing comments for potential technical debt or comment rot, (4) When you need to verify that comments accurately reflect the code they describe.\n\n(example)\nContext: The user is working on a pull request that adds several documentation comments to functions.\nuser: "I've added documentation to these functions. Can you check if the comments are accurate?"\nassistant: "I'll use the comment-analyzer agent to thoroughly review all the comments in this pull request for accuracy and completeness."\n(commentary)\nSince the user has added documentation comments and wants them checked, use the comment-analyzer agent to verify their accuracy against the actual code.\n(/commentary)\n(/example)\n\n(example)\nContext: The user just asked...
SKILL.md
| Name | comment-analyzer |
| Description | Use this agent when you need to analyze code comments for accuracy, completeness, and long-term maintainability. This includes: (1) After generating large documentation comments or docstrings, (2) Before finalizing a pull request that adds or modifies comments, (3) When reviewing existing comments for potential technical debt or comment rot, (4) When you need to verify that comments accurately reflect the code they describe.\n\n(example)\nContext: The user is working on a pull request that adds several documentation comments to functions.\nuser: "I've added documentation to these functions. Can you check if the comments are accurate?"\nassistant: "I'll use the comment-analyzer agent to thoroughly review all the comments in this pull request for accuracy and completeness."\n(commentary)\nSince the user has added documentation comments and wants them checked, use the comment-analyzer agent to verify their accuracy against the actual code.\n(/commentary)\n(/example)\n\n(example)\nContext: The user just asked... |
qyl
Question Your Logs — AI Observability Platform
Landing page: https://ancplua.github.io/qyl/
What qyl Does
| Collects | OTLP receiver with idempotent ingestion (retry-safe) |
| Instruments | Roslyn source generators for zero-config GenAI telemetry |
| Visualizes | Real-time dashboard with SSE streaming |
| Integrates | MCP server and GitHub Copilot for AI agent observability |
Tech Stack
| Layer | Technology |
|---|---|
| Runtime | .NET 10.0 LTS, C# 14 |
| Frontend | React 19, Vite 7, Tailwind CSS 4 |
| Storage | DuckDB (columnar, upsert-based) |
| Protocol | OpenTelemetry 1.40 GenAI Semantic Conventions |
| Schema | TypeSpec → OpenAPI → C#/DuckDB/TypeScript |
Components
| Package | Purpose |
|---|---|
qyl.collector | OTLP receiver, DuckDB storage, REST API, embedded dashboard |
qyl.copilot | GitHub Copilot integration with AG-UI tool rendering |
qyl.hosting | App orchestration framework (QylRunner) |
qyl.servicedefaults | .NET instrumentation library with OTel setup |
qyl.servicedefaults.generator | Roslyn source generator for GenAI/DB interceptors |
qyl.instrumentation.generators | DuckDB insert + interceptor source generators |
qyl.mcp | MCP server for AI agent integration |
qyl.protocol | Shared types (BCL-only, no dependencies) |
Quick Start
Hosted
https://qyl-api-production.up.railway.app
Docker
docker build -f src/qyl.collector/Dockerfile -t qyl .
docker run -d -p 5100:5100 -p 4317:4317 -v ~/.qyl:/data qyl
From Source
git clone https://github.com/ANcpLua/qyl.git
cd qyl
dotnet run --project src/qyl.collector
Instrument Your .NET App
Add the service defaults package to automatically instrument GenAI calls:
// Program.cs
builder.AddQylServiceDefaults();
This auto-instruments:
IChatClientcalls (Microsoft.Extensions.AI)- Token usage, latency, model info
- Full OTel 1.40 GenAI semantic conventions
Set the exporter endpoint:
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:5100"
Use with Any OTel App
qyl accepts standard OTLP from any language/framework:
# Point any OpenTelemetry SDK at qyl
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:5100"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
Supported protocols:
- OTLP/HTTP (port 5100)
- OTLP/gRPC (port 4317)
Architecture
+------------------+ +------------------+
| Your .NET App | | Any OTel App |
| (servicedefaults)| | (Python, Go..) |
+--------+---------+ +--------+---------+
| |
| OTLP |
+----------------+-----------------------+
v
+----------------------------+
| qyl.hosting |
| (QylRunner) |
+-------------+--------------+
| orchestrates
v
+----------------------------+
| qyl.collector |
| (ASP.NET) |
+---+------+------+-----+---+
| | | |
+---------+ +---+---+ | +--+--------+
v v v | v v
+----------+ +----------+ | | +----------+ +----------------+
| DuckDB | | Dashboard| | | | MCP | | qyl.copilot |
| (storage)| | (React) | | | | (agents) | | (GitHub Copilot)|
+----------+ +----------+ | | +----------+ +-------+--------+
| | |
+-----+--+-----+ SSE / AG-UI
| Insights | |
| Materializer | v
+--------------+ GitHub Copilot
AG-UI Tool Rendering
qyl.copilot exposes observability tools to GitHub Copilot via SSE streaming with AG-UI event conventions.
Tools (via ObservabilityTools):
| Tool | Description |
|---|---|
search_spans | Search spans by service name, status, time range |
get_trace | Get all spans for a trace ID |
get_genai_stats | GenAI usage statistics (requests, tokens, costs) |
search_logs | Search logs by severity, body text, time range |
get_storage_stats | Storage statistics (span/log/session counts, size) |
list_sessions | List spans belonging to a session |
get_system_context | Pre-computed system context (zero query cost) |
Each tool is wrapped by DelegatingAIFunction which applies CopilotMetrics (counters, histograms) and
CopilotInstrumentation (OTel spans).
Endpoints:
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/copilot/chat | Chat (SSE streaming) |
| GET | /api/v1/copilot/workflows | List workflows |
| POST | /api/v1/copilot/workflows/{name}/run | Execute workflow (SSE) |
| GET | /api/v1/copilot/status | Auth status |
| GET | /api/v1/copilot/executions | Execution history |
| GET | /api/v1/copilot/executions/{id} | Execution details |
SSE events use AG-UI convention: tool_call and tool_result event names.
Insights Materializer
Background service that pre-computes system context every 5 minutes (10-second warmup delay).
| Materializer | Computes |
|---|---|
TopologyMaterializer | Service discovery, AI model usage |
ProfileMaterializer | Latency percentiles (P50/P95/P99), token costs, trends |
AlertsMaterializer | Error spikes, cost drift, slow operations |
Results are stored in the materialized_insights table and served via get_system_context with zero query cost at read
time.
Ports
| Port | Protocol | Purpose |
|---|---|---|
| 5100 | HTTP | REST API, Dashboard, OTLP/HTTP |
| 4317 | gRPC | OTLP/gRPC ingestion |
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
QYL_PORT | 5100 | HTTP API port |
QYL_GRPC_PORT | 4317 | gRPC OTLP port (0=disable) |
QYL_DATA_PATH | ./qyl.duckdb | DuckDB file location |
QYL_TOKEN | (none) | Auth token |
QYL_MAX_RETENTION_DAYS | 30 | Telemetry retention |
QYL_MAX_SPAN_COUNT | 1000000 | Max spans before cleanup |
QYL_MAX_LOG_COUNT | 500000 | Max logs before cleanup |
QYL_CLEANUP_INTERVAL_SECONDS | 300 | Cleanup interval |
QYL_OTLP_CORS_ALLOWED_ORIGINS | * | CORS origins (CSV) |
GenAI Telemetry
qyl captures OpenTelemetry 1.40 GenAI semantic conventions:
| Attribute | Description |
|---|---|
gen_ai.provider.name | Provider (openai, anthropic, etc) |
gen_ai.request.model | Model name |
gen_ai.usage.input_tokens | Prompt tokens |
gen_ai.usage.output_tokens | Completion tokens |
gen_ai.response.finish_reasons | Stop reason |
TypeSpec-First Design
All types are defined in TypeSpec and generated downstream:
core/specs/*.tsp
↓ (tsp compile)
core/openapi/openapi.yaml
↓ (nuke Generate)
┌───┴───┬───────┬────────┐
↓ ↓ ↓ ↓
C# DuckDB TS JSON Schema
Never edit *.g.cs or api.ts — edit TypeSpec and regenerate.
Idempotent Ingestion
Spans use ON CONFLICT (span_id) DO UPDATE — SDKs can safely retry on network errors without creating duplicates.
Mutable fields (tokens, status, cost) are updated; immutable fields (trace_id, name, start_time) are preserved.
Development
# Full build (TypeSpec → Docker)
nuke Full
# Regenerate types from TypeSpec
nuke Generate --force-generate
# Run tests
dotnet test
# Dashboard dev server (hot reload)
cd src/qyl.dashboard && npm run dev
# Collector only
dotnet run --project src/qyl.collector
Project Structure
core/ # TypeSpec schemas (source of truth)
eng/ # NUKE build system
src/
qyl.collector/ # Backend API service
qyl.copilot/ # GitHub Copilot integration (AG-UI)
qyl.dashboard/ # React frontend
qyl.hosting/ # App orchestration (QylRunner)
qyl.mcp/ # MCP server
qyl.protocol/ # Shared types (BCL-only)
qyl.servicedefaults/ # OTel instrumentation library
qyl.servicedefaults.generator/ # Roslyn source generator
qyl.instrumentation.generators/ # DuckDB insert + interceptor generators
tests/ # Test projects
License
MIT